Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
874 views
in Technique[技术] by (71.8m points)

rust - What is the inferred type of a vector of closures?

I tried to create vector of closures:

fn main() {
    let mut vec = Vec::new();

    vec.push(Box::new(|| 10));
    vec.push(Box::new(|| 20));

    println!("{}", vec[0]());
    println!("{}", vec[1]());
}

That yielded the following error report:

error[E0308]: mismatched types
 --> src/main.rs:5:23
  |
5 |     vec.push(Box::new(|| 20));
  |                       ^^^^^ expected closure, found a different closure
  |
  = note: expected type `[closure@src/main.rs:4:23: 4:28]`
             found type `[closure@src/main.rs:5:23: 5:28]`
  = note: no two closures, even if identical, have the same type
  = help: consider boxing your closure and/or using it as a trait object

I fixed it by specifying the type explicitly:

let mut vec: Vec<Box<Fn() -> i32>> = Vec::new();

What is the inferred type of vec and why is it that way?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Each closure has an auto-generated, unique, anonymous type. As soon as you add the first closure to the vector, that is the type of all items in the vector. However, when you try to add the second closure, it has a different auto-generated, unique, anonymous type, and so you get the error listed.

Closures are essentially structs that are created by the compiler that implement one of the Fn* traits. The struct contains fields for all the variables captured by the closure, so it by definition needs to be unique, as each closure will capture different numbers and types of variables.

Why can't it just infer Box<Fn() -> i32>?

"can't" is a tough question to answer. It's possible that the compiler could iterate through all the traits of every type that is used to see if some intersection caused the code to compile, but that feels a bit magical to me. You could try opening a feature request or discussing it on one of the forums to see if there is general acceptance of such an idea.

However, Rust does try to make things explicit, especially things that might involve performance. When you go from a concrete struct to a trait object, you are introducing indirection, which has the possibility of being slower.

Right now, the Fn* traits work the same as a user-constructed trait:

trait MyTrait {
    fn hello(&self) {}
}

struct MyStruct1;
impl MyTrait for MyStruct1 {}

struct MyStruct2;
impl MyTrait for MyStruct2 {}

fn main() {
    let mut things = vec![];
    things.push(MyStruct1);
    things.push(MyStruct2);
}
error[E0308]: mismatched types
  --> src/main.rs:14:17
   |
14 |     things.push(MyStruct2);
   |                 ^^^^^^^^^ expected struct `MyStruct1`, found struct `MyStruct2`
   |
   = note: expected type `MyStruct1`
              found type `MyStruct2`

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...