【问题标题】:Implement trait for closure type alias实现闭包类型别名的特征
【发布时间】:2015-11-20 11:39:33
【问题描述】:

我有这个闭包类型别名:

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));
}

当我为ClosureTypeBox&lt;Fn(i32) -&gt; i32&gt; 实现特征Trait 时,如果我正确理解类型别名,则相同:

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));

然而变量 ac 被函数 with_one(x: Box&lt;Fn(i32) -&gt; i32&gt;) -&gt; i32 接受,换句话说,它们似乎对于函数 with_one 具有相同的类型(Box&lt;Fn(i32) -&gt; i32&gt;)但不同(Box&lt;[closure &lt;anon&gt;:24:22: 24:35]&gt; 和 @987654340 @) 用于 Trait 实现。

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

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

【问题讨论】:

    标签: closures rust traits type-alias


    【解决方案1】:

    我相信这是由于从具体类型到特征对象类型的自动强制(即不存在)。

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

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

    对于bd,这些强制已在lets 的分配位置发生。

    但是,对于 trait 方法,编译器不会执行强制转换。这是泛型的常见行为(并且特征是通过泛型实现的——它们的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`
    

    【讨论】:

    • 感谢您的回答,确实将 a 或 c 转换为 Box&lt;Fn(i32) -&gt; i32&gt; 有效。还有一个错字更正,在第一块代码下是 bd 而不是 bc
    猜你喜欢
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 2018-04-11
    • 2015-02-20
    相关资源
    最近更新 更多