为什么在没有Deref胁迫其中一个字符串的情况下,不能在Rust中连接两个字符串?

时间:2016-10-07 12:20:25

标签: rust

这样可行:

let hello = "Hello ".to_string();
let world = "world!";

let hello_world = hello + world;

但这并不是:

let hello = "Hello ".to_string();
let world = "world!".to_string();

let hello_world = hello + world;

但这样做:

let hello = "Hello ".to_string();
let world = "world!".to_string();

let hello_world = hello + &world;

这是因为String需要指向第二个string slice的原始String的指针吗?如果是这样,为什么?

2 个答案:

答案 0 :(得分:7)

答案分为两部分。

第一部分是+涉及使用an Add trait implementation。它仅适用于:

impl<'a> Add<&'a str> for String

因此,字符串连接仅在以下情况下有效:

  • 左手边是String
  • 右手边可以强制为&str

注意:与许多其他语言不同,添加将使用左手侧参数。

因此,第二部分是在预期&str时可以使用哪种论点?

显然,&str可以按原样使用:

let hello = "Hello ".to_string();
let hello_world = hello + "world!";

否则,对实施Deref<&str>的类型的引用将起作用,结果String这样做&String有效:

let hello = "Hello ".to_string();
let world = "world!".to_string();

let hello_world = hello + &world;

还有其他什么实现?他们都有问题。

  • impl<'a> Add<String> for &'a str需要预先支付,这不如追加
  • 那么有效
  • impl Add<String> for String当一个足够
  • 时,不必要地消耗两个参数
  • impl<'a, 'b> Add<&'a str> for &'b str隐藏无条件内存分配

最后,Rust的哲学解释了不对称的选择,尽可能明确。

或者更明确一点,我们可以通过检查操作的算法复杂性来解释选择。假设左侧的大小为M而右侧的大小为N,那么:

  • impl<'a> Add<&'a str> for String是O(N)(摊销)
  • impl<'a> Add<String> for &'a str是O(M + N)
  • impl<'a, 'b> Add<&'a str> for &'b str是O(M + N)
  • impl Add<String> for String是O(N)(摊销)......但需要分配/克隆右侧的任何内容。

答案 1 :(得分:2)

standard library实现以下内容:

impl<'a> Add<&'a str> for String

您注意到的正是这一点,您只能向&str添加String

这有以下优点:

  • 使用&str切片
  • 使用&String(因为它取消引用&amp; str)
  • 保留旧字符串(已添加)