将元素添加到不可变向量 rust
Add element to immutable vector rust
我正在尝试利用函数式编程和递归在 Rust 中创建用户输入验证函数。如何 return 一个不可变向量,其中一个元素连接到末尾?
fn get_user_input(output_vec: Vec<String>) -> Vec<String> {
// Some code that has two variables: repeat(bool) and new_element(String)
if !repeat {
return output_vec.add_to_end(new_element); // What function could "add_to_end" be?
}
get_messages_from_user(output_vec.add_to_end(new_element)) // What function could "add_to_end" be?
}
其他所有功能都有:
push
将可变向量添加到可变向量
append
将一个元素添加到可变向量的末尾
concat
将不可变向量添加到不可变向量
???
将一个元素添加到不可变向量的末尾
我能够开始工作的唯一解决方案是使用:
[write_data, vec![new_element]].concat()
但这似乎效率低下,因为我只为一个元素创建一个新向量(因此大小在编译时已知)。
您将 Rust 与一种您只能引用对象的语言混淆了。在 Rust 中,代码可以拥有对象的独占所有权,因此你不需要对改变一个 可以 共享的对象那么小心,因为你 知道对象是否共享。
例如,这是有效的JavaScript代码:
const a = [];
a.push(1);
这是可行的,因为 a
不包含数组,它包含对数组的 引用。1 const
防止 a
被重新指向不同的对象,但它 不会 使数组本身不可变。
因此,在这些类型的语言中,纯函数式编程试图避免改变任何状态,例如将一个项目推入一个作为参数的数组中:
function add_element(arr) {
arr.push(1); // Bad! We mutated the array we have a reference to!
}
相反,我们这样做:
function add_element(arr) {
return [...arr, 1]; // Good! We leave the original data alone.
}
根据你的函数签名,你在 Rust 中拥有的是一个 完全不同的场景! 在你的情况下,output_vec
由函数本身拥有,并且没有程序中的其他实体可以访问它。因此,没有理由避免改变它,如果这是你的目标:
fn get_user_input(mut output_vec: Vec<String>) -> Vec<String> {
// Add mut ^^^
您必须记住,任何 non-reference 都是拥有的价值。 &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()); // E0382
}
表达式 x.len()
导致 compile-time 错误,因为向量 x
被 移动 到函数参数中,而我们没有不再拥有它。
那么为什么函数不应该改变它现在拥有的向量呢?调用方不能再使用了。
总而言之,函数式编程在 Rust 中看起来有点不同。在其他无法传达“我给你这个对象”的语言中,你必须避免改变给定的值,因为调用者可能不希望你更改它们。在 Rust 中,谁拥有一个值是明确的,参数反映了:
- 参数是一个值(
Vec<String>
)吗?该函数现在拥有该值,调用者放弃了它并且不能再使用它。如果需要,请改变它。
- 参数是否为不可变引用 (
&Vec<String>
)?该函数不拥有它,并且它无论如何也不能改变它,因为 Rust 不允许。您可以克隆它并对克隆体进行变异。
- 参数是否为可变引用 (
&mut Vec<String>
)?调用者必须显式地为函数提供一个可变引用,因此允许函数对其进行修改——但函数仍然不拥有该值。该函数可以改变它、克隆它或两者兼而有之——这取决于该函数应该做什么。
如果您按值接受参数,那么如果您出于任何原因需要更改它,就没有理由不使用它 mut
。请注意,此细节(函数参数的可变性)甚至不是函数 public 签名的一部分,因为这与调用者无关。他们把物品送人了。
请注意,对于具有类型参数的类型(如 Vec
),所有权的其他表达方式也是可能的。这里有几个例子(这不是一个详尽的列表):
Vec<&String>
:您现在拥有一个矢量,但您不拥有它包含引用的 String
个对象。
&Vec<&String>
:您被授予 read-only 访问字符串引用向量的权限。您可以克隆此向量,但您仍然无法更改字符串,例如只能重新排列它们。
&Vec<&mut String>
:您可以 read-only 访问 可变 字符串引用的向量。您无法重新排列字符串,但可以自行更改字符串。
&mut Vec<&String>
:同上但相反:允许重新排列字符串引用但不能更改字符串。
1 一个很好的理解方式是 JavaScript 中的 non-primitive 值总是 Rc<RefCell<T>>
的值,所以你' 将句柄传递给具有内部可变性的对象。 const
只会使 Rc<>
不可变。
我正在尝试利用函数式编程和递归在 Rust 中创建用户输入验证函数。如何 return 一个不可变向量,其中一个元素连接到末尾?
fn get_user_input(output_vec: Vec<String>) -> Vec<String> {
// Some code that has two variables: repeat(bool) and new_element(String)
if !repeat {
return output_vec.add_to_end(new_element); // What function could "add_to_end" be?
}
get_messages_from_user(output_vec.add_to_end(new_element)) // What function could "add_to_end" be?
}
其他所有功能都有:
push
将可变向量添加到可变向量
append
将一个元素添加到可变向量的末尾
concat
将不可变向量添加到不可变向量
???
将一个元素添加到不可变向量的末尾
我能够开始工作的唯一解决方案是使用:
[write_data, vec![new_element]].concat()
但这似乎效率低下,因为我只为一个元素创建一个新向量(因此大小在编译时已知)。
您将 Rust 与一种您只能引用对象的语言混淆了。在 Rust 中,代码可以拥有对象的独占所有权,因此你不需要对改变一个 可以 共享的对象那么小心,因为你 知道对象是否共享。
例如,这是有效的JavaScript代码:
const a = [];
a.push(1);
这是可行的,因为 a
不包含数组,它包含对数组的 引用。1 const
防止 a
被重新指向不同的对象,但它 不会 使数组本身不可变。
因此,在这些类型的语言中,纯函数式编程试图避免改变任何状态,例如将一个项目推入一个作为参数的数组中:
function add_element(arr) {
arr.push(1); // Bad! We mutated the array we have a reference to!
}
相反,我们这样做:
function add_element(arr) {
return [...arr, 1]; // Good! We leave the original data alone.
}
根据你的函数签名,你在 Rust 中拥有的是一个 完全不同的场景! 在你的情况下,output_vec
由函数本身拥有,并且没有程序中的其他实体可以访问它。因此,没有理由避免改变它,如果这是你的目标:
fn get_user_input(mut output_vec: Vec<String>) -> Vec<String> {
// Add mut ^^^
您必须记住,任何 non-reference 都是拥有的价值。 &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()); // E0382
}
表达式 x.len()
导致 compile-time 错误,因为向量 x
被 移动 到函数参数中,而我们没有不再拥有它。
那么为什么函数不应该改变它现在拥有的向量呢?调用方不能再使用了。
总而言之,函数式编程在 Rust 中看起来有点不同。在其他无法传达“我给你这个对象”的语言中,你必须避免改变给定的值,因为调用者可能不希望你更改它们。在 Rust 中,谁拥有一个值是明确的,参数反映了:
- 参数是一个值(
Vec<String>
)吗?该函数现在拥有该值,调用者放弃了它并且不能再使用它。如果需要,请改变它。 - 参数是否为不可变引用 (
&Vec<String>
)?该函数不拥有它,并且它无论如何也不能改变它,因为 Rust 不允许。您可以克隆它并对克隆体进行变异。 - 参数是否为可变引用 (
&mut Vec<String>
)?调用者必须显式地为函数提供一个可变引用,因此允许函数对其进行修改——但函数仍然不拥有该值。该函数可以改变它、克隆它或两者兼而有之——这取决于该函数应该做什么。
如果您按值接受参数,那么如果您出于任何原因需要更改它,就没有理由不使用它 mut
。请注意,此细节(函数参数的可变性)甚至不是函数 public 签名的一部分,因为这与调用者无关。他们把物品送人了。
请注意,对于具有类型参数的类型(如 Vec
),所有权的其他表达方式也是可能的。这里有几个例子(这不是一个详尽的列表):
Vec<&String>
:您现在拥有一个矢量,但您不拥有它包含引用的String
个对象。&Vec<&String>
:您被授予 read-only 访问字符串引用向量的权限。您可以克隆此向量,但您仍然无法更改字符串,例如只能重新排列它们。&Vec<&mut String>
:您可以 read-only 访问 可变 字符串引用的向量。您无法重新排列字符串,但可以自行更改字符串。&mut Vec<&String>
:同上但相反:允许重新排列字符串引用但不能更改字符串。
1 一个很好的理解方式是 JavaScript 中的 non-primitive 值总是 Rc<RefCell<T>>
的值,所以你' 将句柄传递给具有内部可变性的对象。 const
只会使 Rc<>
不可变。