2

我想在 rust 中实现一个函数,计算数组或 Vec 的范数

对于 Vec<f64> 我会将函数编写为

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()
}    

但是有没有办法通过使用特征将两个版本组合成一个函数。我在想类似的东西

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 不可索引。有可能以某种方式做到这一点吗?也许带有迭代器特征或其他东西?

4

2 回答 2

5

首先,Vec<T>实现Deref. [T]这意味着&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));
}
于 2021-11-05T21:26:46.307 回答
3

除了 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那么您正在寻找的特征就是。

于 2021-11-06T06:00:20.660 回答