通用性状实施中的寿命



我想制作一个类似于以下结构的特征(我的特殊用例更为复杂,但这捕获了我遇到的问题和错误(。我遇到的问题是最后一生中的一生。我认为我需要将它们挤入特征定义中,但我不确定如何。我该如何整理一生,所以这会编译?

Rust Playground链接到代码

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

类型签名

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

desugars to

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

我认为您的最后一个特征不会编译,因为它本质上是不安全的。

您的意义实际上等于:

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

这意味着,对于任何类型的T任何 lifetime 'aT实现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,以使其完全安全。

相关内容

  • 没有找到相关文章

最新更新