【问题标题】:the From<&String> trait is not implemented for the type String没有为 String 类型实现 From<&String> 特征
【发布时间】:2015-10-08 03:36:02
【问题描述】:

我将离开this 文章,试图编写一个同时接受String 和&str 的函数,但我遇到了问题。我有以下功能:

pub fn new<S>(t_num: S) -> BigNum where S: Into<String> {
    let t_value = t_num.into();
    let t_digits = t_value.len();
    BigNum { value: t_value, digits: t_digits }
}

BigNum 是一个简单的结构,但问题是当我尝试使用 &amp;collections::string::String 调用它时出现错误:

let line = "123456".to_string()
let big = bignum::BigNum::new(&line)

main.rs:23:15: 23:34 error: the trait `core::convert::From<&collections::string::String>` is not implemented for the type `collections::string::String` [E0277]
main.rs:23     let big = bignum::BigNum::new(&line);

我的印象是 &amp;String 将被隐式分解为 &amp;str 不是吗?在这种情况下,Into 特征会将&amp;str 转换为我可以使用的字符串。我做错了什么?

【问题讨论】:

    标签: string rust ownership


    【解决方案1】:

    正如 DK. 所提到的,这对于 Rust Into 特征是不可能的,因为缺少 Into&lt;String&gt; for &amp;String 的实现。我找不到这背后的原因,但你可以创建自己的 Trait 来解决这个问题:

    pub trait IntoString {
        fn into(self) -> String;
    }
    
    impl IntoString for &String {
        fn into(self) -> String {
            self.to_string()
        }
    }
    impl IntoString for &str {
        fn into(self) -> String {
            self.to_string()
        }
    }
    
    impl IntoString for String {
        fn into(self) -> String {
            self
        }
    }
    
    pub fn new<S>(t_num: S) -> BigNum where S: IntoString {
        let t_value = t_num.into();
        let t_digits = t_value.len();
        BigNum { value: t_value, digits: t_digits }
    }
    

    【讨论】:

      【解决方案2】:

      您将两个不同的进程混为一谈。

      首先是强制;特别是Deref coercion。当编译器看到你有一个&amp;U,但你想要一个&amp;T 时,就会发生这种情况。只要有impl Deref&lt;Target=T&gt; for U,它就会为你强制执行。这就是为什么&amp;String 会强制转换为&amp;str

      然而,当编译器替换泛型类型参数时,这个不会发挥作用。当你说BigNum::new(&amp;line) 时,编译器看到的是你试图在它期望S 的地方传递&amp;String;因此,S 必须是&amp;String,因此S 必须实现Into&lt;String&gt; 并且......哦,不!它没有! BOOM! 永远不会触发强制,因为编译器从不需要强制任何东西;未实现的类型约束是另一个问题。

      在这种特殊的情况下,你应该做什么取决于你的情况:

      • 你可以传递一个String;使用lineline.clone()。这是最有效的,因为您始终可以传递您不再需要的拥有的String,并避免额外分配。

      • 您可以改为使用 &amp;SS: ?Sized + AsRef&lt;str&gt;,这不允许您传递拥有的字符串,但如果您总是要分配,这可能更符合人体工程学。

      以下是两者的实际应用示例:

      use std::convert::AsRef;
      
      fn main() {
          take_a_string(String::from("abc"));
          // take_a_string(&String::from("abc")); // Boom!
          take_a_string("def");
      
          // take_a_string_ref(String::from("abc")); // Boom!
          take_a_string_ref(&String::from("abc"));
          take_a_string_ref("def");
      }
      
      fn take_a_string<S>(s: S)
      where S: Into<String> {
          let s: String = s.into();
          println!("{:?}", s);
      }
      
      fn take_a_string_ref<S: ?Sized>(s: &S)
      where S: AsRef<str> {
          let s: String = s.as_ref().into();
          println!("{:?}", s);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-27
        • 2019-12-08
        • 2015-11-11
        • 2015-07-15
        • 2018-10-23
        • 2020-03-31
        • 1970-01-01
        相关资源
        最近更新 更多