为什么在 Rust 函数中注释类型时会出现错误 "expected type argument"?

Why do I get the error "expected type argument" when I annotate a type in a Rust function?

我正在研究 Rust 的 capnproto library。因为 Rust 在某些情况下可以推断类型,所以我可以这样做:

let mut message = ::capnp::message::Builder::new_default();

无需知道消息的类型。如果我想将对 message 的引用传递给一个函数,我现在需要知道什么消息是让函数知道要发生什么。

一般情况下有什么方便的方法吗?

到目前为止,我已经完成了以下工作:

let testing: () = message;

因编译器错误而失败:

error[E0308]: mismatched types
   --> src/main.rs:197:18
    |
197 |                 let temp: () = message;
    |                           ^^^^^^^ expected (), found struct `capnp::message::Builder`

但是当我键入如下注释我的函数时:

fn example_fn(message: capnp::message::Builder) {...}

我收到如下错误:

error[E0243]: wrong number of type arguments: expected 1, found 0
  --> src/main.rs:72:32
   |
72 | fn dump_capnp_to_file(message: capnp::message::Builder, filename: &str) {
   |                                ^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument

错误:由于先前的错误而中止

我是 C++ 背景的 Rust 新手;对不起,如果这是一个菜鸟问题!

Rust 不会 在函数参数位置推断类型。这是设计使然,如 Rust language FAQ 所述:

Why aren't function signatures inferred?

In Rust, declarations tend to come with explicit types, while actual code has its types inferred. There are several reasons for this design:

  • Mandatory declaration signatures help enforce interface stability at both the module and crate level.

  • Signatures improve code comprehension for the programmer, eliminating the need for an IDE running an inference algorithm across an entire crate to be able to guess at a function’s argument types; it’s always explicit and nearby.

  • Mechanically, it simplifies the inference algorithm, as inference only requires looking at one function at a time.

由于 capnp::message::Builder<A> 接受类型参数 A,您需要通过给 A 一个值来限定参数的类型:

fn dump_capnp_to_file(message: capnp::message::Builder<SomeType>, filename: String) {
//                                                    ^^^^^^^^^^

或者让你的函数也通用,这样它就可以接受任何类型 A:

fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String) {
//                   ^^^                                 ^^^

设置界限 A

如果您选择最后一个选项,您可能需要额外的 trait bounds to allow you to do different things with message inside the function. For example, you might want to send message to another thread, which requires that Builder<A> implement Send. Builder has the following impl (reference):

impl <A> Send for Builder<A> where A: Send + Allocator

表示Builder<A>可以实现Send,但前提是A实现SendAllocator。您可以在 A:

上设置您自己的绑定(要求)
fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String)
    where A: Send + Allocator
{
    // multi-threaded code...
}

或者(也许稍微好一点),将 Builder<A> 直接绑定到 Send

fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String)
    where capnp::message::Builder<A>: Send

那么您将只能在实现 Send.

Builder 上调用 dump_capnp_to_file