你将Rust和一种只有对象引用的语言混淆了。在Rust中,代码可以对对象拥有独占所有权,因此您不需要像处理可能共享的对象时那样小心,因为您知道该对象是否被共享。
例如,以下是有效的JavaScript代码:
const a = [];
a.push(1);
这能正常工作是因为
a
不包含数组,它包含一个指向数组的引用。
1 const
防止
a
被指向到另一个对象,但它
不会使数组本身成为不可变的。
所以,在这些类型的语言中,纯函数式编程试图避免任何状态的变异,例如将项目推送到作为参数接受的数组中:
function add_element(arr) {
arr.push(1);
}
相反,我们会这样做:
function add_element(arr) {
return [...arr, 1];
}
在 Rust 中,根据您的函数签名,您拥有的是完全不同的场景!在您的情况下,output_vec
是由函数本身拥有的,程序中没有其他实体可以访问它。因此,如果这是您的目标,就没有理由避免对其进行变异:
fn get_user_input(mut output_vec: Vec<String>) -> Vec<String> {
// Add mut ^^^
请记住,任何非引用值都是所拥有的值。&Vec<String>
是对某个其他元素拥有的向量的不可变引用,但 Vec<String>
是这段代码拥有的向量,没有其他人可以访问。
不信?下面是一个简单的破坏性代码示例:
fn take_my_vec(y: Vec<String>) { }
fn main() {
let mut x = Vec::<String>::new();
x.push("foo".to_string());
take_my_vec(x);
println!("{}", x.len());
}
x.len()
导致编译时错误,因为向函数参数中传递的向量
x
已被
移动,我们不再拥有它。
那么为什么函数不能变异它现在所拥有的向量呢?调用者无法再使用它了。
综上所述,在Rust中,函数式编程看起来有些不同。在其他没有办法通信“我正在给你这个对象”的语言中,必须避免变异您收到的值,因为调用者可能不希望您更改它们。在Rust中,谁拥有一个值是清楚的,并且参数反映了这一点:
- 参数是值(
Vec<String>
)吗?函数现在拥有该值,调用者已经放弃并且不能再使用它。如果需要,请对其进行变异。
- 参数是不可变引用(
&Vec<String>
)吗?函数不拥有它,并且无法变异它,因为Rust不允许。您可以克隆它并使克隆变异。
- 参数是可变引用(
&mut Vec<String>
)吗?调用者必须明确给出一个可变引用,因此授权给函数变异它——但函数仍然不拥有该值。函数可以变异它、克隆它或两者都可以——这取决于函数的预期行为。
如果按值接受参数,则没有多少理由不对其进行
mut
,如果因任何原因需要更改它。请注意,此详细信息(函数参数的可变性)甚至不是函数的公共签名的一部分,因为这不是调用方的业务。他们已经放弃了该对象。
请注意,在具有类型参数的类型(如
Vec
)中,还可以使用其他所有权表达式。以下是一些示例(这不是详尽无遗的列表):
-
Vec<&String>
: 您现在拥有一个向量,但您不拥有其中包含的引用到
String
对象。
-
&Vec<&String>
: 您被授予对字符串引用向量的只读访问权限。您可以克隆这个向量,但仍然不能更改字符串,例如只能重新排列它们。
-
&Vec<&mut String>
: 您被授予对
可变字符串引用向量的只读访问权限。你不能重新排列字符串,但你可以更改字符串本身。
-
&mut Vec<&String>
: 类似于上面但相反: 您被允许重新排列字符串引用,但不能更改字符串。
1一个好的思考方式是,在JavaScript中,非原始值总是Rc<RefCell<T>>
的值,因此您正在传递一个具有内部可变性的对象句柄。 const
仅使Rc<>
不可变。
mut output_vec: Vec<String>
?你不可变地取值的原因是什么?(或者output_vec
应该是一个引用?) - cdhowieadd_to_end
应该返回一个新的Vec
吗?看起来它实际上是let mut result = output_vec.clone(); result.push(new_element)
。 - HerohtarVec::push()
的等效方法,这不是纯函数式的。你会发现,在Rust中,由于其借用系统,纯函数式方法并不适用。此外,请注意,与诸如JavaScript或Java这样的语言不同,你实际上从未真正拥有一个对象(而是总是拥有引用),但在Rust中,你可以拥有一个对象本身,这就是output_vec
所代表的。你不必担心不要改变不属于你的对象,因为output_vec
属于该函数,因为它是按值获取的。 - cdhowie