是否有可能专注于静态寿命?

时间:2016-05-05 14:45:08

标签: rust

我想从&'static str专攻&'a 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 个答案:

答案 0 :(得分:7)

Rust 1.25.0没有任何类型的专业化。如果我正确地阅读the specialization RFC,那么即使实施RFC,也会支持的终身专业化:

  

特质系统设计中的一个硬约束是调度   不能依赖终身信息。特别是,我们都不能,   并且不应该允许基于生命期的专业化

     
      
  • 我们不能,因为当编译器实际生成代码(“trans”)时,生命周期信息已被删除 - 所以我们没有   想知道什么专业化适用。

  •   
  • 我们不应该,因为终生推理是微妙的,并且往往导致违反直觉的结果。例如,您很容易失败   获得'static即使它适用,因为推理是选择   与其他约束相匹配的最小生命周期。

  •   

(强调我的)

链接中还有一些示例表明了一些具体问题。

我建议使用Cow来处理“拥有或借用”案件。

答案 1 :(得分:-1)

我在阅读了这个duplicated post之后写了这个答案,询问如何定义一个方法/函数,当它传递一个静态字符串或一个非静态字符串时表现不同。

这是不可能的,因此解决方法可能是使用包装器类型将字符串参数包装在enum中:

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)。< / p>

这有助于提高助记符和代码可读性吗?我非常肯定这只适用于初学者或偶尔的Rust程序员,而不适合经验丰富的Rustaceans。