实现封闭类型别名的特征

Oto*_*obo 5 closures traits rust type-alias

我有这个闭包类型别名:

type ClosureType = Box<Fn(i32) -> i32>;
Run Code Online (Sandbox Code Playgroud)

这个特点:

trait Trait {
    fn change(&self, y: i32) -> i32;
}
Run Code Online (Sandbox Code Playgroud)

和这些功能:

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));
}
Run Code Online (Sandbox Code Playgroud)

当我实现性状TraitClosureType或者Box<Fn(i32) -> i32>是相同的,如果我理解正确类型的别名:

impl Trait for ClosureType {
    fn change(&self, y: i32) -> i32{
        self(y)
    }
}
Run Code Online (Sandbox Code Playgroud)

要么

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

对于变量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));
Run Code Online (Sandbox Code Playgroud)

对于变量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));
Run Code Online (Sandbox Code Playgroud)

但是变量ac从函数中被接受with_one(x: Box<Fn(i32) -> i32>) -> i32,换句话说,它们Box<Fn(i32) -> i32>对于函数而言具有相同的type(),with_one但对于实现而言具有不同的(Box<[closure <anon>:24:22: 24:35]>and Box<fn(i32) -> i32 {plus_one}Trait

我觉得我在这里错过了一些东西,但不确定是什么,您能启发我吗?

您可以在这个生锈的游乐场找到所有代码。

Vla*_*eev 6

我相信这是由于从具体类型到特征对象类型的自动强制(即它的缺失)而发生的。

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

with_one(a as Box<Fn(i32) -> i32>);
with_one(c as Box<Fn(i32) -> i32>);
Run Code Online (Sandbox Code Playgroud)

因为b这些d强制已经在lets 的分配地点发生了。

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