能否专注于静态生命周期?

5
我想从 &'a str 中专门使用 &'static str:
use std::borrow::Cow;

struct MyString {
    inner: Cow<'static, str>,
}

impl From<&'static str> for MyString {
    fn from(x: &'static str) -> Self {
        MyString {
            inner: Cow::Borrowed(x),
        }
    }
}

impl<T: Into<String>> From<T> for MyString {
    fn from(x: T) -> Self {
        MyString {
            inner: Cow::Owned(x.into()),
        }
    }
}

fn main() {
    match MyString::from("foo").inner {
        Cow::Borrowed(..) => (),
        _ => {
            panic!();
        }
    }

    let s = String::from("bar");
    match MyString::from(s.as_ref()).inner {
        Cow::Owned(..) => (),
        _ => {
            panic!();
        }
    }

    match MyString::from(String::from("qux")).inner {
        Cow::Owned(..) => (),
        _ => {
            panic!();
        }
    }
}

要点是,MyString 将静态分配的字符串字面量存储为 &'static str,而将所有其他字符串存储为 String。这使得 MyString 避免了生命周期参数(即 MyString<'a>),这对于我的 API 至关重要,同时允许调用者传入任何类型的字符串,并且让 MyString 自动执行正确的操作。
问题在于该代码无法编译:
error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `MyString`:
  --> src/main.rs:15:1
   |
7  | impl From<&'static str> for MyString {
   | ------------------------------------ first implementation here
...
15 | impl<T: Into<String>> From<T> for MyString {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyString`

有没有什么技巧可以让我做我想做的事情?如果没有,终身专业化是否是Rust将要支持的功能?

2个回答

10
Rust 1.51.0没有任何形式的特化。如果我正确理解特化RFC,那么即使实现了RFC,也不会支持生命周期特化: “特质系统设计中的一个硬性约束是派发不能依赖于生命周期信息。特别地,我们不能也不应该允许基于生命周期的特化。”:
· 我们不能,因为当编译器开始生成代码(“trans”)时,生命周期信息已被擦除,所以我们不知道哪些特化适用。 · 我们不应该,因为生命周期推断是微妙的,并且通常会导致直觉上令人费解的结果。例如,即使适用,您也可能很容易失败而无法获得`'static'`,因为推断正在选择与其他约束匹配的最小寿命。
(强调我的)
链接中有一些进一步的例子,说明了一些具体问题。
我建议使用`Cow`来处理“拥有或借用”的情况。

-1
在阅读了这篇重复的帖子之后,我写下了这个答案,该帖子询问如何定义一个方法/函数,当传递静态字符串或非静态字符串时,它会有不同的行为。
这是不可能的,因此解决方法可能是使用包装类型将字符串参数包装在枚举中:
enum MyString {
    Static(&'static str),
    Heap(String),
}

fn bar(arg: &MyString) {
    match arg {
        &MyString::Static(ref name) => println!("my first pc was {}", name),
        &MyString::Heap(ref name) => println!("I dont know {}", name),
    }
}

fn main() {
    let mut v = Vec::new();

    let forever: &'static str = "zx-spectrum";
    let local: &str = &"commodore64".to_string();

    v.push(MyString::Static(forever));

    // ERROR: try to insert 'a lifetime
    // v.push(Mystring::Static(local));
    v.push(MyString::Heap(local.to_string()));

    v.push(MyString::Heap("muggle".to_string()));

    bar(&v[0]);
    bar(&v[1]);
}

MyString 将静态分配的字符串字面量存储为 &'static str,将所有其他字符串存储为 String

正如下面的评论所指出的那样,标准库提供了适合借用/拥有情况的类型:智能指针 Cow

在此示例中使用的枚举 MyString 只是用于管理字符串类型的特定枚举。

唯一的区别在于枚举及其变体的命名更加具体化,与特定用法相关:MyString::Static("forever")Cow::Borrowed("forever")MyString::Heap(str)Cow::Owned(str)

这有助于提高记忆和代码可读性吗?我相信这仅适用于 Rust 初学者或偶尔编写 Rust 的程序员,而不适用于经验丰富的 Rustaceans。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接