I am playing around with Rust's capnproto library. Because Rust can infer types in some situations, I can do things like this:
let mut message = ::capnp::message::Builder::new_default();
Without having to know the type of message. If I want to pass a reference to message
into a function, I now need to know what message is to let the function know what to expect.
Is there a convenient way to do this in general?
So far I have done the following:
let testing: () = message;
which fails with the compiler error:
error[E0308]: mismatched types
--> src/main.rs:197:18
|
197 | let temp: () = message;
| ^^^^^^^ expected (), found struct `capnp::message::Builder`
But when I type annotate my function as follows:
fn example_fn(message: capnp::message::Builder) {...}
I get an error like:
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
error: aborting due to previous error
I'm very new to Rust coming from a C++ background; sorry if this a rookie question!
Rust will not infer types in function parameter position. This is by design, as the Rust language FAQ states:
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.
Since capnp::message::Builder<A>
takes a type parameter A
, you need to qualify the type of the parameter by giving A
a value:
fn dump_capnp_to_file(message: capnp::message::Builder<SomeType>, filename: String) {
// ^^^^^^^^^^
or else make your function also generic so it can accept any type A
:
fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String) {
// ^^^ ^^^
A
If you take the last option, you might want additional 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
which means that Builder<A>
can implement Send
, but only when A
implements Send
and Allocator
. You can make that your own bound (requirement) on A
:
fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String)
where A: Send + Allocator
{
// multi-threaded code...
}
Alternatively (and maybe slightly better), bound Builder<A>
with Send
directly:
fn dump_capnp_to_file<A>(message: capnp::message::Builder<A>, filename: String)
where capnp::message::Builder<A>: Send
Then you will only be able to call dump_capnp_to_file
on a Builder
that implements Send
.