实现闭包类型别名

时间:2015-08-26 12:19:57

标签: closures rust traits type-alias

我有这个闭包类型别名:

type ClosureType = Box<Fn(i32) -> i32>;

这个特性:

trait Trait {
    fn change(&self, y: i32) -> i32;
}

和这些功能:

fn with_one(x: Box<Fn(i32) -> i32>) -> i32 {
    x(1)
}

fn plus_one(x: i32) -> i32 {
    x+1
}

fn main() {
    let a = Box::new(|x: i32|{x+1});
    let b: ClosureType = Box::new(|x: i32|{x+1});
    let c = Box::new(plus_one);
    let d: ClosureType = Box::new(plus_one);
    println!("{}", a.change(1));
    println!("{}", b.change(1));
    println!("{}", c.change(1));
    println!("{}", d.change(1));
    println!("{}", with_one(a));
    println!("{}", with_one(b));
    println!("{}", with_one(c));
    println!("{}", with_one(d));
}

当我为TraitClosureType实现特性Box<Fn(i32) -> i32>时,如果我理解正确,则输入相同的别名:

impl Trait for ClosureType {
    fn change(&self, y: i32) -> i32{
        self(y)
    }
}

impl Trait for Box<Fn(i32) -> i32> {
    fn change(&self, y: i32) -> i32{
        self(y)
    }
}

对于变量a我得到:

<anon>:32:22: 32:31 error: no method named `change` found for type
`Box<[closure <anon>:28:22: 28:35]>` in the current scope 
<anon>:32     println!("{}", a.change(1));

和变量c我得到:

<anon>:34:22: 34:31 error: no method named `change` found for type
`Box<fn(i32) -> i32 {plus_one}>` in the current scope
<anon>:34     println!("{}", c.change(1));

但是,函数a接受变量cwith_one(x: Box<Fn(i32) -> i32>) -> i32,换句话说,它们似乎与函数{{1}具有相同的类型(Box<Fn(i32) -> i32>)但with_one实现的不同(Box<[closure <anon>:24:22: 24:35]>Box<fn(i32) -> i32 {plus_one})。

我觉得我在这里遗漏了一些东西,但不确定它是什么,你能开导我吗?

您可以在this rust playground找到所有代码。

1 个答案:

答案 0 :(得分:4)

我认为这是由于从具体类型到特质对象类型的自动强制(即缺席)而发生的。

当你调用with_one()时,编译器能够从函数参数类型中理解你想要一个特征对象,因此它会插入自动强制:

with_one(a as Box<Fn(i32) -> i32>);
with_one(c as Box<Fn(i32) -> i32>);

对于bd,这些强制行为已经发生在let s的作业地点。

但是,对于特征方法,编译器不执行强制。这是围绕泛型的常见行为(并且特征是在泛型上实现的 - 它们的Self类型本质上是所有特征方法的隐式类型参数)。例如,Rust在使用泛型时也不执行deref强制:

trait MyStringLike {}

impl<'a> MyStringLike for &'a str {}

fn function<T: MyStringLike>(t: T) {}

let s: String = "abcde".into();
function(&s);  // the trait `main::MyStringLike` is not implemented for the type `&collections::string::String`