Зачем нужен приведение, когда замыкание передается в качестве аргумента объекта черты? - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь создать черту, которая должна абстрагироваться от функций / замыканий с другим количеством аргументов.Примерно так:

trait MyTrait {}

impl MyTrait for Box<Fn() -> &'static str> {}

impl MyTrait for Box<Fn(u8) -> u8> {}

Изначально я планировал использовать его так:

fn myf<F: MyTrait>(_fun: F) {}

fn main() {
    myf(Box::new(|i: u8| i + 2))
}

Но этот код не работает с ошибкой:

error[E0277]: the trait bound `std::boxed::Box<[closure@src/main.rs:11:18: 11:31]>: MyTrait` is not satisfied

Когда я произнесув этом поле все компилируется правильно:

myf(Box::new(|i: u8| i + 2) as Box<Fn(_) -> _>)

Playground

Почему компилятор Rust не может вывести эту черту без приведения?Мой подход (с использованием приведения) правильный, или есть более простой способ?Я предпочитаю включать trivial_casts предупреждение для моих проектов, и этот синтаксис вызывает его.

1 Ответ

0 голосов
/ 25 мая 2018

Это вещь, о которой обычно забывают: каждое замыкание - это отдельная структура, которая реализует Fn: Fn - это признак, а не структура, и реализации признака не транзитивны.

ЗдесьВот небольшой пример, который показывает эту точку:

trait Base {}
trait Derived {}
struct Foo {}

impl Base for Derived {}

impl Derived for Foo {}

fn myf<T>(_t: Box<T>)
where
    T: Base + ?Sized,
{
}

fn main() {
    let foo = Box::new(Foo {});
    //myf(foo) // does not compile
    myf(foo as Box<Derived>)
}

То, что вы действительно хотели сделать, это:

trait MyTrait {}

impl<T> MyTrait for T
where
    T: Fn() -> &'static str,
{
}

impl<T> MyTrait for T
where
    T: Fn(u8) -> u8,
{
}

fn myf<F>(_fun: Box<F>)
where
    F: MyTrait,
{
}

fn main() {
    myf(Box::new(|i: u8| i + 2))
}

Но это не может быть скомпилировано, потому что есть две конфликтующие реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...