rust - 如何编写一个具有返回引用的方法的特征并正确实现它?

标签 rust

我想编写一个具有诸如 foo(&self) -> &T 之类的方法的特征,并将其实现为具体类型而不是引用。这是我尝试过的,但我无法让它工作:

trait GetRef<'a> {
    fn get(&self) -> &'a u8;
}

// U8Ref works fine
struct U8Ref<'a> {
    data: &'a u8
}

impl<'a> GetRef<'a> for U8Ref<'a> {
    fn get(&self) -> &'a u8 {
        self.data
    }
}

struct U80 { data: u8 }
struct U81 { data: u8 }
struct U82 { data: u8 }
struct U83 { data: u8 }

// works, but is not exactly what I want (API changes, and does not work on
// &mut U80, see main() below)
impl<'a> GetRef<'a> for &'a U80 {
    fn get(&self) -> &'a u8 {
        &self.data
    }
}

impl<'a> GetRef<'a> for U81 {
    fn get(&self) -> &'a u8 {
        // E0495: cannot infer an appropriate lifetime for lifetime parameter
        // in generic type due to conflicting requirements
        &self.data
    }
}

impl<'a> GetRef<'a> for U82 {
    //E0308: lifetime mismatch
    fn get(&'a self) -> &'a u8 {
        &self.data
    }
}

impl<'a> GetRef<'a> for &'a mut U83 {
    fn get(&self) -> &'a u8 {
        // again E0495
        &self.data
    }
}

fn main() {
    let u0 = U80 {data :0};

    // works
    (&u0).get();

    // no method named `get` found for type `U80` in the current scope
    u0.get();

    // no method named `get` found for type `&mut U80` in the current scope
    (&mut u0).get();
}

最佳答案

你的特质的实现需要限制所涉及的生命周期。对于您的 U8Ref 情况,生命周期将比 self 长,但在 U80 和类似情况下,它们将是相等的。

该特征需要有两个生命周期作为输入才能表达这一点,所以让我们将 self 生命周期添加为 :

trait GetRef<'a, 's> {
    fn get(&'s self) -> &'a u8;
}

现在这些都是明确的,我们可以编写impl。首先,对于持有引用的人:

struct U8Ref<'a> {
    data: &'a u8
}

// Straightforward; we can separate the self and return reference lifetimes.
impl<'a, 's> GetRef<'a, 's> for U8Ref<'a> {
    fn get(&'s self) -> &'a u8 {
        self.data
    }
}

现在,对于之前更困难的情况,我们可以明确告诉编译器生命周期是相同的:

struct U80 { data: u8 }

// The impl is only valid when &self has the same lifetime as the &u8 returned.
impl<'a> GetRef<'a, 'a> for U80 {
    fn get(&'a self) -> &'a u8 {
        &self.data
    }
}

并用它来检查它的编译:

fn main() {
    let mut u0 = U80 {data :0};
    let uval: u8 = 7;
    let ur0 = U8Ref { data: &uval };

    ur0.get();

    (&u0).get();

    u0.get();

    (&mut u0).get();
    {
        // Check that it works when U8Ref's reference outlives itself.
        let v = 0u8;
        let u: &u8;
        {
            let r = U8Ref { data: &v };
            u = r.get();
        }
        println!("{}", u);
    }
}

Playground link

关于rust - 如何编写一个具有返回引用的方法的特征并正确实现它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40449512/

相关文章:

rust - 当我尝试在未确定大小的类型上手动实现 Ord 和 Eq 时,为什么会得到 `trait bound ` [T]: std::marker::Sized` is not satisfied?

rust - 压低借来的箱子

java - 是否可以一起使用 Java、SWIG 和 Rust?

real-time - 我如何在 Rust 中进行实时编程?

winapi - Rust WINAPI输出HMODULE值

multithreading - 为什么等待线程完成的 Rust 代码不起作用?

performance - 为什么我的 Rust 程序比等效的 Java 程序慢?

rust - 关于 Rust Setter

rust - 当 self 可变时返回可变引用,否则引用

rust - 有没有一种方法可以将SDL2字体呈现为等距?