这样可行:
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
的指针吗?如果是这样,为什么?
答案 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)