< 返回版块

kalxd 发表于 2022-01-08 21:34

trait FromValue<'a> {
    fn from_value(value: &'a str) -> Self;
}

impl<'a> FromValue<'a> for String {
    fn from_value(value: &'a str) -> Self {
        value.into()
    }
}

我创建一个FromValue<'a>这样的trait,带有一个生命周期变量。

struct Value;

impl Value {
    fn get<'a, T>(&'a self) -> T where T: FromValue<'a> {
        T::from_value("hello")
    }
}

创建一个空struct,作用去调用from_value,即使self并不需要。

最后,我创建了几个函数,再去调用这个get

// 编译通过
fn try_get1<'a, T>() -> T where T: FromValue<'a> {
    Value.get()
}

// 编译通过
fn try_get2() -> String {
    let value = Value;
    value.get()
}

// 编译失败,遇到生命周期问题,提示value不够长久
fn try_get3<'a, T>() -> T where T: FromValue<'a> {
    let value = Value;
    value.get()
}

它们作用都是调用Value.get,为什么只有try_get3失败了,value.get()不是应该会得带有所有权的返回值的吗? 感谢不吝赐教。


Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ae65e5d97ebdf0d19474b72e204481ac

评论区

写评论
作者 kalxd 2022-01-09 18:44

太感谢了,真是醍醐灌顶。

我还是太年轻,见笑了;看来需要提高一下知识水平。

苦瓜小仔 2022-01-09 00:12

为什么只有 try_get3 失败了?

impl Value {
    fn get<'a, T>(&'a self) -> T where T: FromValue<'a> {
        T::from_value("hello")
    }
}

因为约束了返回值 T 需要和 self 一样长的生命周期,所以

fn try_get3<'b, T>() -> T where T: FromValue<'b> { 
    let value = Value; // 这个值从函数内产生,生命周期为 'a
    value.get() //  生命周期也为 'a(与 self 实例保持一致,即生命周期最长不超过 value ),无法转化成 'b 那么长(也就是不够长)
}

当你把 &'a self 的约束放宽成 &self:

impl Value {
    fn get<'a, T>(&self) -> T where T: FromValue<'a> {
        T::from_value("hello") 
    }
}

try_get3 可以通过编译。因为 try_get3 相当于返回具有 'static 生命周期的数据:

fn try_get3<'b, T>() -> T where T: FromValue<'b> { 
    let value = Value; // 这个值从函数内产生,生命周期为 'a
    value.get() //  生命周期为 'static(与 T::from_value("hello") 保持一致),可以转化成 'b (因为  'static: 'b)
}

为什么 try_get1 两种情况下都可以通过?

因为这是有效的:

fn f() -> &'static Value { &Value }

即 Value 作为返回值,其引用的生命周期是 'static 的,而 Value.get() 的实际形式为 (&Value).get() ,所以

fn try_get1<'a, T>() -> T where T: FromValue<'a> {
    Value.get() // 返回的值总是 'static 的(无论跟 self 还是跟 T::from_value 保持一致的生命周期)
}

纠正几个小问题

一、生命周期“变量”的说法是从何而来?只有生命周期、生命周期参数、生命周期注解、lifetime bounds 这些术语,而 “变量” 的概念是很明确的。

二、“value.get() 不是应该会得带有所有权的返回值的吗?” —— 不一定。因为 T: FromValue<'a> ,该 trait bound 没有限定必须为引用(泛型 T 可以是引用或者非引用类型),当你有以下实现时:

impl<'a, 'b: 'a> FromValue<'b> for &'a str {
     fn from_value(value: &'b str) -> Self { value }
}

// 或者
impl<'a> FromValue<'a> for &'a str {
     fn from_value(value: &'a str) -> Self { value }
}

你的例子一样可以运行

Edit: playground

1 共 2 条评论, 1 页