为闭包类型别名实现trait

8

我有一个闭包类型的别名:

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

这个 trait:

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

当我为`ClosureType`或者`Box i32>`这个类型别名实现特质`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<Fn(i32) -> i32>) -> i32中接受的,换句话说,它们对于函数with_one来说具有相同的类型(Box<Fn(i32) -> i32>),但在Trait实现中,它们的类型不同(Box<[closure <anon>:24:22: 24:35]>Box<fn(i32) -> i32 {plus_one})。
我感觉我在这里漏掉了什么,但不确定是什么,请问您能否给我一些启示?
您可以在此 Rust playground中找到所有代码。
1个回答

6
我认为这是由于从具体类型到特质对象类型的自动强制转换(即其缺失)所导致的。
当您调用with_one()时,编译器能够从函数参数类型中理解您需要一个特质对象,因此它会插入自动强制转换。
with_one(a as Box<Fn(i32) -> i32>);
with_one(c as Box<Fn(i32) -> i32>);

对于变量 b d ,这些强制转换已经在它们在let中的赋值处发生。

然而,对于特质方法,编译器不执行强制转换。这是泛型周围常见的行为(并且特质是基于泛型实现的-它们的Self类型实际上是所有特质方法的隐式类型参数)。例如,当使用泛型时,Rust也不执行解引用强制转换:

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<Fn(i32) -> i32>可以解决问题。 另外,对您的回答进行了一个错别字更正,在第一个代码块下是bd而不是bc - Otobo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接