Время жизни в реализации общего признака - PullRequest
2 голосов
/ 25 июня 2019

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

Rust детская площадка ссылка на код

trait MyTrait<TIn> {
    fn f<TOut, F>(f: F, x: Self) -> TOut
    where
        F: Fn(TIn) -> TOut;
}

impl<T> MyTrait<T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(T) -> TOut,
    {
        f(x)
    }
}

impl<T> MyTrait<T> for &T
where
    T: Clone,
{
    fn f<TOut, F>(f: F, x: &T) -> TOut
    where
        F: Fn(T) -> TOut,
    {
        f(x.clone())
    }
}

// This impl fails to compile:
impl<T> MyTrait<&T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(&T) -> TOut,
    {
        f(&x)
    }
}

Ответы [ 2 ]

1 голос
/ 27 июня 2019

Сигнатура типа

impl<T> MyTrait<&T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(&T) -> TOut,
    {
    }
}

обращается к

impl<'a, T: 'a> MyTrait<&'a T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: for<'r> Fn(&'r T) -> TOut,
    {
    }
}

, что является более общим, чем сигнатура типа черты.Использование

impl<'a, T: 'a> MyTrait<&'a T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(&'a T) -> TOut,
    {
    }
}

позволило бы это скомпилировать, но ограничить реализацию либо недействительным, либо небезопасным кодом.

impl<'a, T: 'a> MyTrait<&'a T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(&'a T) -> TOut,
    {
        //panic!(); or
        f(unsafe { &*(&x as *const T) })
    }
}

Небезопасная версия может легко вызвать использование после освобождения, например

println!("{:?}", String::f(|x: &String| x, "aa".to_string()));

Вместо этого вы можете переместить границы на F вверх ( Детская площадка )

trait MyTrait<TIn, F, TOut>
where
    F: Fn(TIn) -> TOut,
{
    fn f(f: F, x: Self) -> TOut;
}

impl<T, F, TOut> MyTrait<T, F, TOut> for T
where
    F: Fn(T) -> TOut,
{
    fn f(f: F, x: T) -> TOut {
        f(x)
    }
}

impl<T, F, TOut> MyTrait<T, F, TOut> for &T
where
    T: Clone,
    F: Fn(T) -> TOut,
{
    fn f(f: F, x: &T) -> TOut {
        f(x.clone())
    }
}

impl<T, F, TOut> MyTrait<&T, F, TOut> for T
where
    F: Fn(&T) -> TOut,
{
    fn f(f: F, x: T) -> TOut {
        f(&x)
    }
}
0 голосов
/ 25 июня 2019

Я думаю, что ваша последняя черта не компилируется, потому что она по сути небезопасна.

Ваш импл фактически эквивалентен:

impl<'a, T> MyTrait<&'a T> for T

Это означает, что для любого типа Tи любой срок действия 'a, T реализует MyTrait<&'a T>.В частности, если 'a является, например, 'static, то T реализует MyTrait<&'static T>.Таким образом, я мог бы написать что-то вроде этого:

fn foo(x: &'static i32) -> &'static i32{
     x
}

fn main() {
    let sp: &'static i32 = {
        <i32 as MyTrait<&'static i32>>::f(foo, 42)
    };
    *sp = 0; //crash!
}

(я не уверен, но я думаю, что вам даже не нужно ' static здесь, чтобы сделать его сбой. Я не могу проверить это, потому что это делаетне компилировать!).

Этот случай запрещен системой типов, потому что черта требует:

F: Fn(TIn) -> TOut;

, но когда TIn является &T, это фактически:

F: for <'r> Fn(&'r TIn) -> TOut;

, который является строго более общим, чем черта.

Единственный способ, которым я вижу, что вы можете написать это безопасно, это что-то вроде этого:

impl<T: 'static> MyTrait<&'static T> for T {
    fn f<TOut, F>(f: F, x: T) -> TOut
    where
        F: Fn(&'static T) -> TOut,
    {
        f(...)
    }
}

Но этовероятно, не то, что вы хотите, потому что вы не можете использовать x в качестве аргумента.Обратите внимание, что вам даже нужно сделать T: 'static, чтобы сделать его полностью безопасным.

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