字符串字面量是不可变的吗?

4
我正在阅读 Rust 书籍以学习 Rust,目前正在学习所有权。它提到:
“我们已经见过字符串字面量了,在其中字符串值是硬编码到我们的程序中的。字符串字面量很方便,但并不适用于我们可能想要使用文本的每种情况。一个原因是它们是不可变的。”
下面的代码可以正常运行,我改变了 a 的值,如果不可变字符串可以被更改,那么问题在哪里?
fn main() {
   let mut a = "Hello";
   println!("{}", a);
   a = " World";
   println!("{}", a);
}

3
在你的例子中,a 是一个对不可变切片进行可变绑定。你可以改变它绑定的不可变切片(就像你所做的那样),但你仍然无法修改这些切片本身。 - eggyal
3
例如,执行a.make_ascii_uppercase()将会失败。 - eggyal
4
欢迎来到“值”和“变量名”的区别。即使这些值本身是不可变的,您仍然可以将可变的变量名重新分配给新的值。 - JMAA
1个回答

6
由Rust编译器生成的可执行二进制文件在只读数据段rodata中包含字符串文字"Hello"和"World"。
$ cargo build --release
$ readelf -x .rodata target/release/demo | grep Hello
  0x0003c000 48656c6c 6f000000 0a576f72 6c640000 Hello....World..

由于这些字面量被放置在不可变的部分,操作系统禁止对其进行修改。

fn main() {
    let mut a: &'static str = "Hello";
    println!("{}", a);

    unsafe { (a.as_ptr() as *mut u8).write(42) };
    println!("{}", a);
}

$ cargo run
Hello
Segmentation fault

然而,变量a的类型为&str,是一个指向字符串切片的指针,它存在于堆栈中。因此,让a先指向"Hello"的地址,然后再指向"World"的地址是完全有效的。


编辑:关于unsafe块的信息

我们想要将一些东西写入到a所指向的地址上,以证明它确实存储在只读区域中。

a声明为mut a: &str,意味着变量是可变的,但数据(字符串字面值)是不可变的(与mut a: &mut str相对)。 因此,编译器阻止我们使用a.as_mut_ptr()来获取可变(即可写)指向底层字节的指针。

相反,我们需要做一个小技巧:使用a.as_ptr()并将返回的const *u8转换为mut *u8。最后,写入指针需要一个unsafe块,因为你可以违反Rust的内存安全性,这可能会导致像上面显示的分段错误等不良后果。


你能解释一下 unsafe 这行是什么意思吗? - DevonDahon
1
@DevonDahon编辑了答案,包括不安全行的解释。 - linuskmr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接