ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入解析 Rust 编译错误 E0618:Attempted to call something which isn‘t a function nor a method

深入解析 Rust 编译错误 E0618:Attempted to call something which isn‘t a function nor a method 深入解析 Rust 编译错误 E0618Attempted to call something which isnt a function nor a method【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本文聚焦于 rustc 的类型检查诊断体系系统讲解 E0618attempted to call something which isnt a function nor a method的触发场景、rustc 内部生成路径与可执行的修复方案。你将理解为什么X::Entry()与0i32()会被编译器拒绝、该错误如何从类型检查器typeck的 callee 解析流程中产生并能针对单位变体、整数、方法调用形态误写等场景给出正确的改写代码。错误定义只有函数与方法可以被()调用E0618 是 rustc 在“对既非函数也非方法的表达式使用调用语法()”时报出的编译期错误。Rust 中expr(args)这一语法形态只能作用于可调用对象callable即函数、函数指针、实现Fn/FnMut/FnOncetrait 的闭包与结构体以及元组结构体构造器/元组变体构造器等其他类型即便语法上写得像“调用”类型检查阶段也会将其拒绝。本错误的官方说明位于 compiler/rustc_error_codes/src/error_codes/E0618.md其注册的错误码行为由 rustc_hir_typeck crate 实现见下文源码分析。触发场景与最小复现官方文档给出的典型错误代码如下enum X { Entry, } X::Entry(); // error: expected function, tuple struct or tuple variant, // found X::Entry // Or even simpler: let x 0i32; x(); // error: expected function, tuple struct or tuple variant, found i32第一个例子中X::Entry是枚举的单位变体unit variant它只是一个值不携带任何数据也不具备可调用语义对它使用()调用语法自然不合法。第二个例子中x是i32类型的普通整数变量rustc 明确将其诊断信息格式化为expected function, tuple struct or tuple variant, found \i32——其中found 部分如实描述了被误当作函数去调用的“真实身份”。合法的调用示例与之相对只有真正的可调用项才允许接()。官方文档补充了最基础的对照示例// We declare a function: fn i_am_a_function() {} // And we call it: i_am_a_function();这里i_am_a_function是一个零参数函数调用i_am_a_function()合法。同理带字段的枚举变体Entry(i32)、元组结构体struct P(i32);、实现了Fn系列 trait 的类型都可以通过()调用。编译器如何诊断从 callee 解析到 E0618要真正理解 E0618需要追溯到 rustc 对调用表达式的类型检查流程。对call_expr的检查集中在 compiler/rustc_hir_typeck/src/callee.rs 的check_call相关逻辑中编译器会先对被调用表达式callee执行自动解引用autoderef并尝试解析其可调用签名。当解析完全失败得到None即既非内置调用、也非重载的Fn调用、更非闭包调用时走兜底分支若被调用方是形如foo(...)的路径rustc 会先尝试窃取/改写诊断判断能否将foo(a)改写为a.foo()方法调用形态修正见 callee.rs随后调用report_invalid_callee最终在 callee.rs 内部创建 E0618 诊断并把它作为类型错误传播Ty::new_error使后续编译阶段不再基于错误类型继续推导。诊断体本身的定义在 compiler/rustc_hir_typeck/src/diagnostics.rs#[derive(Diagnostic)] #[diag(expected function, found {$found}, code E0618)] pub(crate) struct InvalidCallee { #[primary_span] pub span: Span, pub found: String, }found字段就是错误信息中被调用对象的“真实身份”字符串它由 callee.rs 组装若被调用对象是单位结构体或单位变体则格式化为struct \path或enum variant path否则格式化为对应类型i32 之类的类型名。这就是 E0618 报错文案的最终来源。rustc 为 E0618 提供的“加分”诊断建议从源码看report_invalid_callee不仅给出主错误还会根据具体情况附加有参考价值的子诊断单位变体/单位结构体的括号删除建议当被调用者是Ctor(kind, CtorKind::Const)且调用不含任何实参时rustc 认为极可能是“误把构造写法当调用”会给出移除括号的机器可应用MachineApplicable建议提示X::Entryis a unit variant, and does not take parentheses to be constructed对应代码位于 callee.rs。跨行调用的缺失分号建议若调用表达式跨多行、且被调用对象本身又是一个调用表达式编译器会怀疑漏了语句结束分号建议在合适位置补;对应 issue #51055/#106515 场景见 callee.rs。定义处标注编译器会尝试在函数/局部变量/类型路径的定义处追加 span label如\x has type i32、Entry defined here帮助开发者快速定位问题源头callee.rs。被遮蔽的同名函数提示若x()中的x是局部绑定而当前 crate 恰有同名的函数项rustc 会额外指出该函数定义位置并提示“它被局部绑定遮蔽了”callee.rs。实战修复对照表结合 E0618 的常见误写可按下列策略修改代码场景错误写法修复方式单位枚举变体被误当函数X::Entry()去掉括号改为X::Entry作为值使用若确需带负载数据应改声明为元组变体Entry(i32)后以X::Entry(v)构造整数/普通值变量被调用let x 0i32; x();去掉()变量本身不承载任何可执行逻辑若意图是执行某个函数改为调用真正的函数i_am_a_function()方法调用写成了自由调用strlen(s)若strlen实为s的方法改为方法语法s.strlen()rustc 给出的提示同样会推荐这一改写上一语句漏分号导致粘连调用跨行将表达式“拼接”成调用按诊断建议在合适位置补分号结束前一语句再另起调用局部绑定遮蔽同名函数let foo 1; foo();且另有fn foo()依据“同名函数被遮蔽”的提示重命名局部变量或显式路径调用函数相关测试与进一步阅读读者可结合 error code 文档正文与类型检查源码核对以下资料错误说明原文compiler/rustc_error_codes/src/error_codes/E0618.md诊断体错误文案与码绑定diagnostics.rs检查触发与子建议自动解引用、方法化改写、单位变体去括号、缺失分号等callee.rs编译错误代码总览目录位于 compiler/rustc_error_codes可通过x.py test tests/ui一类的测试流程观察相关 ui 测试输出。小结E0618 是 rustc 在类型检查阶段对“非法调用非函数对象”的统一答复Rust 的()调用语法只服务于函数、可调用 trait 实现者以及带元组形式的构造器/变体。本文既给出了最小复现与修复对照也溯源了错误在rustc_hir_typeckcallee 解析、InvalidCallee诊断定义中的完整生成链路——理解这一过程后当遇到形形色色的“不能调用”场景时便能依据诊断中found的真实类型快速定位并改写为合法的 Rust 代码。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表