一旦所有者超出范围,谁是串联字符串的所有者?

Who is the owner of a concatenated string once its owner goes out of scope?

我正在学习 Rust,chapter 8.2 of the Rust Programming Language book 提出了一些疑问:

let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 is {}", s2);

If the push_str method took ownership of s2, we wouldn’t be able to print its value on the last line.

我理解这一点以及连接仅添加对字符串的引用而没有获得其所有权这一事实。这应该意味着如果 s2 超出范围或被更改,连接的字符串应该被释放或更改但它没有发生:

let mut s1 = String::from("foo");
{
    let mut s2 = String::from("bar");
    s1.push_str(&s2[..]);
    println!("s2 is {}", s2);

    println!("s1 is {}", s1);
    s2 = String::from("lol");

    println!("s2 is {}", s2);
}
println!("Value after change is {}", s1);

由于拼接后的字符串只是对字符串s2的引用,而s1并没有得到字符串的所有权,一旦s2超出范围,谁是串联字符串的所有者?

Stringstr 存储为连续的 UTF-8 字节数组。

String "foo"                         &str "bar"
[ len: 3 | data:┐ ]                  [ len: 3 | data:┐ ]
                │                                    │
                v                                    v
                [ f | o | o ]   [ more memory... ]   [ b | a | r ]

当您执行 s1.push_str(&s2[..]) 时,s2 的字节被复制到 s1 拥有的内存的末尾(可能重新分配以腾出更多空间),留下 s2原样。

              ┌────────────────────┐
              v                    │
[ f | o | o | b | a | r ]        [ b | a | r ]

底层字节必须连续这一事实意味着无法使用 Rust 的 String/&str 类型执行非复制追加操作。这样的操作需要字符串类型实现,例如,字符串块的链表而不是单个连续数组。