自动铸造Vec到阵列

时间:2015-09-25 19:09:17

标签: arrays vector casting rust

在尝试将Vec<u8>发送给期望&[u8]的函数的不同方法时,我犯了一个实际有效的“错误”。我写了一些示例代码来说明这一点:

fn sum(v: &[u8]) -> u8 {
    let mut s = 0u8;
    for x in v.iter() {
        s = s + x;
    }
    return s;
}

fn main() {
    let myarr = [1u8, 2u8, 3u8];
    let myvec = vec![1u8, 2u8, 3u8];

    println!("{}", sum(&myarr));
    println!("{}", sum(&myvec));
}

我对此有几个问题:

  • 为什么以及如何运作?
  • 这两种类型之间是否有自动投射?
  • 它是否会受到任何惩罚,或者只是占用了向量的底层数组的内存位置?
  • 这是否意味着对于这种类型的使用(对数字数组的只读操作)最好使用数组而不是向量作为API?

2 个答案:

答案 0 :(得分:6)

让我们放开一件事:sum函数中有无数组。 Rust有三种相关类型,您可以在此处搜索Stack Overflow或 The Rust Programming Language 以获取有关它们的更多信息:

  1. 切片&[T]
  2. 向量Vec<T>
  3. 数组[T; n]
  4. v参数是 slice ,它只是指向一大块数据和元素数量的指针。

      

    为什么以及如何运作?这两种类型之间是否有自动投射?

    Deref trait在这里发挥作用。这个特征的实现如下:

    impl<T> Deref for Vec<T> {
        type Target = [T];
        fn deref(&self) -> &[T];
    }
    

    这意味着对Vec<T>的任何引用都可以作为对[T]的引用,并从目标类型中获取所有方法。编译器可以理解Deref,但任何类型都可以实现它,因此它只是特殊的。

      

    它是否会受到任何惩罚,或者只是占用了向量的底层数组的内存位置?

    这是零成本转换,这就是编译器为您做的原因。让编译器为你做任何昂贵的事情是非常不寻常的。

      

    这是否意味着对于这种类型的使用,最好使用数组而不是向量作为API?

    绝对!您有百分之百的时间接受&[T]而不是&Vec<T>。除了Vec之外,更多的事情可以提供&[T],而数组就是一个例子。

答案 1 :(得分:3)

您正在查看行动中的Deref特征。如果您具有实现此特征的类型T,并且您调用的函数采用类型为&U的参数,那么&T将调用值deref它是正确的类型。该书有一个chapter左右。

您可以看到Vec的实现here它只是将Vec的指针和长度字段复制到一个几乎免费的新结构中。

你是对的,编写视图而不是拥有类型的函数会更好。只需使用Vec<u8>调用Vec<u8>的{​​{1}}函数,但可以使用&[u8]Vec<u8>调用[u8; 500]的函数,或来自其他地方的&[u8]。同样,功能应尽可能采用&T而不是Box<T>,或&str而不是String