在不复制的情况下取得 String 的所有权

Taking ownership of a &String without copying

上下文

Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a9ffa99023735f4fbedec09e1c7ac55

这是我运行

的人为复制
fn main() {
   let mut s = String::from("Hello World");
   example(&mut s);
}

fn example(s: &mut str) -> Option<String> {
    other_func(Some(s.to_owned()))
    // other random mutable stuff happens
}

fn other_func(s: Option<String>) {
    match s {
        Some(ref s) => other_func2(*s),
        None => panic!()
    }
}

fn other_func2(s: String) {
    println!("{}", &s)
}

和错误

   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `*s` which is behind a shared reference
  --> src/main.rs:12:36
   |
12 |         Some(ref s) => other_func2(*s),
   |                                    ^^ move occurs because `*s` has type `String`, which does not implement the `Copy` trait

问题

在下面的代码中,为什么我不能在不执行某种 clone/copy 的情况下引用 &String?即这不起作用

fn other_func(s: Option<String>) {
    match s {
        Some(ref s) => other_func2(*s),
        None => panic!()
    }
}

但如果我将 *s 替换为 s.to_owned()/s.to_string()/s.clone()

它会起作用

顺便说一句,我知道这可能可以通过重构使用 &str 来解决,但我特别感兴趣的是转向 &String -> String

为什么编译器允许你这样做?

s&String。如果不进行克隆,就无法从 &String 中获取 String。这很明显。

它是从拥有的 String 创建的?编译器不在乎,它是对的。这与以下代码没有区别:

let s: String = ...;
let r: &String = ...;
let s2: String = *r; // Error

这与以下代码没有什么不同,例如,就编译器而言:

let r: &String = ...;
let s: String = *s;

而且我们的开头不再有自有字符串。通常,编译器不跟踪数据流。确实如此 - 当它 type-checks 移动时,它甚至无法确认此引用没有别名。或者不再使用拥有的值。引用只是引用,它们没有给您删除值的权利。

更改在一般情况下是不可行的(例如,编译器必须跟踪跨函数调用的数据流),并且需要某种形式的手动注释来说明“此值是我的”。你已经有了这样的注释——使用一个拥有的值,String,而不是 &String:这正是它的意义所在。