Trait mismatch for function argument

前端 未结 2 534
孤独总比滥情好
孤独总比滥情好 2021-01-22 15:09

I\'ve got one piece of Rust code that compiles and one that\'s very similar that does not.

The one that works:

pub fn do_something(_: Box

        
相关标签:
2条回答
  • 2021-01-22 15:46

    You can't coerce a Box<Box<I>> into a Box<Box<Iterator<Item = f64>>>, for reasons discussed in this question, but you can coerce the inner Box:

    pub fn do_something(_: Box<Box<Iterator<Item = f64>>>) {}
    
    fn main() {
        let iter = Box::new(Box::new(vec![1.0].into_iter()) as Box<Iterator<Item = f64>>);
        //                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        do_something(iter);
    }
    

    Playground.

    This works because a cast is a coercion site. By writing as Box<Iterator<Item = f64>>, you're hinting to the compiler that it should attempt to make the expression to the left fit that type instead of inferring Box<IntoIter<f64>>, because once it's wrapped up in the "outer" Box, you can't change it anymore.

    Alternatively (but less clearly), you could make Box::new(...) a coercion site by explicitly parameterizing Box:

        let iter = Box::<Box<Iterator<Item = f64>>>::new(Box::new(vec![1.0].into_iter()));
    

    Which effectively does the same thing.

    0 讨论(0)
  • 2021-01-22 15:48

    To be honest, I'm no expert in Rust at all, but my expectation would have been that both of the snippets you show do not compile. That is because, as you pointed out, Iterator is a trait and not a type and basically you want do_something to receive any type which implements Iterator. Maybe there exists a shortcut such that the compiler can transform the signature into a generic if one of the types is a trait which could be why is sometimes works, but then I'm also not familiar with the Rust language specification enough.

    Instead of having do_something take something of type Iterator (?) make it a generic of type T where T is trait bound.

    pub fn do_something<T>(_: Box<Box<T>>) 
        where T: Iterator<Item = f64> + Send {}
    
    fn main() {
        let iter = Box::new(Box::new(vec![1.0].into_iter()));
        do_something(iter);
    }
    

    Playground

    Alternatively, you constrain do_something entirely to std::vec::IntoIter and only take parameters of that type.

    pub fn do_something(_: Box<Box<std::vec::IntoIter<f64>>>) {}
    
    fn main() {
        let iter = Box::new(Box::new(vec![1.0].into_iter()));
        do_something(iter);
    }
    

    Playground

    0 讨论(0)
提交回复
热议问题