编写具有适用于 Vec 和数组 [] 的特征的 Rust 函数
Writing rust function with traits working for Vec and array []
我想用 Rust 实现一个函数,计算数组或 Vec 的范数
对于 Vec 我会把函数写成
pub fn vector_norm( vec_a : &Vec<f64> ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
对于 &[f64] 我会做
pub fn vector_norm( vec_a : &[f64] ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
但是有没有办法通过使用 traits 将两个版本组合成一个函数。我在想
pub fn vector_norm<T:std::iter::ExactSizeIterator>
( vec_a : &T ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
这不起作用,因为模板参数 T 不可索引。有可能以某种方式做到这一点吗?也许有迭代器特征或其他东西?
首先,Vec<T>
为 [T]
实现了 Deref
。这意味着 &Vec<f64>
可以隐式转换为 &[f64]
。因此,只需输入 &[f64]
即可:
fn vector_norm(vec_a: &[f64]) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
// &my_vec is implicitly converted to &[f64]
println!("{:?}", vector_norm(&my_vec));
}
但是,如果您想将可接受的值进一步扩大到所有类似切片的类型,也许 AsRef
可能有用:
fn vector_norm<T: AsRef<[f64]>>(vec_a: T) -> f64 {
// use AsRef to get a &[f64]
let vec_a: &[f64] = vec_a.as_ref();
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
println!("{:?}", vector_norm(&my_vec));
}
除了 Aplet 的回答之外,我还要补充一点,如果您使用的东西只会在 for _ in
循环中使用,您可能需要查看 IntoIterator
。
fn vector_norm<T: IntoIterator<Item = f64>>(t: T) -> f64 {
let mut norm = 0f64;
for i in t {
norm += i * i;
}
norm.sqrt()
}
当您编写 for i in t
时,编译器会将其重写为看起来更像这样的内容:
let mut iter = t.into_iter();
loop {
match iter.next() {
None => break,
Some(i) => {
// loop body
}
}
}
因此,如果您只想将输入限制为“在 for 循环中起作用的东西”,IntoIterator
就是您要寻找的特征。
我想用 Rust 实现一个函数,计算数组或 Vec 的范数
对于 Vec
pub fn vector_norm( vec_a : &Vec<f64> ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
对于 &[f64] 我会做
pub fn vector_norm( vec_a : &[f64] ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
但是有没有办法通过使用 traits 将两个版本组合成一个函数。我在想
pub fn vector_norm<T:std::iter::ExactSizeIterator>
( vec_a : &T ) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len(){
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
这不起作用,因为模板参数 T 不可索引。有可能以某种方式做到这一点吗?也许有迭代器特征或其他东西?
首先,Vec<T>
为 [T]
实现了 Deref
。这意味着 &Vec<f64>
可以隐式转换为 &[f64]
。因此,只需输入 &[f64]
即可:
fn vector_norm(vec_a: &[f64]) -> f64 {
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
// &my_vec is implicitly converted to &[f64]
println!("{:?}", vector_norm(&my_vec));
}
但是,如果您想将可接受的值进一步扩大到所有类似切片的类型,也许 AsRef
可能有用:
fn vector_norm<T: AsRef<[f64]>>(vec_a: T) -> f64 {
// use AsRef to get a &[f64]
let vec_a: &[f64] = vec_a.as_ref();
let mut norm = 0 as f64;
for i in 0..vec_a.len() {
norm += vec_a[i] * vec_a[i];
}
norm.sqrt()
}
fn main() {
let my_vec = vec![1.0, 2.0, 3.0];
println!("{:?}", vector_norm(&my_vec));
}
除了 Aplet 的回答之外,我还要补充一点,如果您使用的东西只会在 for _ in
循环中使用,您可能需要查看 IntoIterator
。
fn vector_norm<T: IntoIterator<Item = f64>>(t: T) -> f64 {
let mut norm = 0f64;
for i in t {
norm += i * i;
}
norm.sqrt()
}
当您编写 for i in t
时,编译器会将其重写为看起来更像这样的内容:
let mut iter = t.into_iter();
loop {
match iter.next() {
None => break,
Some(i) => {
// loop body
}
}
}
因此,如果您只想将输入限制为“在 for 循环中起作用的东西”,IntoIterator
就是您要寻找的特征。