使用Rust返回不可变字符串

10
我想从一个 Rust 函数返回一个字符串,但我目前只看到的选项是返回可以修改的 String。虽然这并不是错误的,但我很喜欢以不可变的形式返回一些字符串,例如错误描述。
那么,函数当前是否有任何方法可以将例如Result<Something, String>返回的错误实际上以不可变的方式返回?在仍然返回类似于Str兼容的内容的同时在类型本身中强制执行它是否可能?或者我应该停止担心并总是返回String(像大多数std::io函数一样)?

6
你应该批判性地审视一下为什么你对返回可变类型感到不安。在许多面向对象的编程语言中,避免返回可变类型的引用,因为这会创建可变对象的别名,因此任何调用者都可以轻松地引起奇怪的远距离作用。但在Rust中,这不是一个问题,因为如果你返回一个String,你就返回了它的所有权,并且静态保证没有其他引用它。 - user395760
@delnan在这种情况下,我喜欢不可变的字符串,因为你不能意外地自己修改它们。假设我们仍在谈论错误处理,并且在错误路径中我执行some_processing(message); log(message);。在Python、Java、Haskell等语言中,我确定消息没有被some_processing修改。但是在Rust中就不一定了。即使本地代码具有所有权,第一个函数仍然可能搞砸它。 - viraptor
3
@viraptor,实际上你也可以这样说Rust。如果message是一个字符串(String),你的代码将无法编译,因为message将被移动到函数中。如果它是一个切片(slice),它是不可变的,所以你不能对它进行危险操作。some_processing()修改其参数的唯一方法是通过可变引用传递:some_processing(&mut message),在这里你可以很容易地看到some_processing()修改了它的参数。 - Vladimir Matveev
@VladimirMatveev 太棒了,我没意识到这一点! - viraptor
1个回答

19

Rust采用继承可变性的概念——也就是说,数据是否可变取决于该数据的所有者。因此,如果你的数据是常规的拥有结构(例如String),那么你在返回它后无法影响其可变性。

然而,有一种解决方法。由于Rust是基于值的语言,具有单个字段类型的结构的实例与该类型的值完全相同,因此您可以为类型创建一个包装器,不直接公开其字段,但提供一个getter函数以返回对该字段的不可变引用:

struct ImmutableString(String);

impl ImmutableString {
    #[inline]
    fn get_ref(&self) -> &String { &self.0 }

    // or, even better:

    #[inline]
    fn as_slice(&self) -> &str { self.0.as_slice() }
}

由于编译器优化,这是一个零成本的包装器,两种方法都被内联掉了,但由于这些方法是与结构体内部交互的唯一方式,并且它们只返回不可变引用,因此这样的结构体将实际上是不可变的。

然而,我认为你并不需要所有这些。Rust 的所有权和借用概念消除了在像 C、C++ 或 Java 这样的语言中通常存在的所有可变数据问题,所以只需自然而然地做就好——如果你返回一个 String,那么你放弃了对它的所有控制,让调用者决定他们想要做什么,没有必要加任何限制。


元组结构体仍然可以被解构,但是您可以通过使用可见性规则来防止这种情况。用户仍然可以调用结构体上的方法,但是他们无法解构,因为他们无法导入类型名称。PlayPen:http://is.gd/vrWTVO 由于某种原因,您使用的元组索引语法不起作用,因此我不得不在as_slice()方法中进行解构和捕获。 - Austin B
@Logician,元组结构体需要将其内部字段也公开,以便可以从模块外部访问它们。请自行查看。因此,不需要做其他事情。至于索引语法,我认为Rust主干上有一个PR,但尚未合并。 - Vladimir Matveev
你能展示一下如何在实践中使用它,除了trait实现之外吗?有哪些处理字符串和构造字符串的代码示例?我是Rust的新手,“casting”字符串非常令人讨厌。 - Petrus Theron
@PetrusTheron,你看过 Rust 书中关于字符串的章节吗?https://doc.rust-lang.org/book/2018-edition/ch08-02-strings.html 我认为它有很多关于如何处理和构建字符串的例子。否则我担心你的问题太泛泛了;如果你能想出一些具体的问题,请随时在 SO 上提出它作为一个单独的问题。 - Vladimir Matveev
1
感谢@VladimirMatveev,“拥有可变性”让我恍然大悟。 - Petrus Theron

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