简体   繁体   English

如何在Rust中修改矢量的元素?

[英]How can I modify elements of a vector in place in Rust?

I am trying to pass an immutable reference to a Vec (a slice) to a function which will fill the Vec with incrementing values, and then iterate over them again replacing some of those values with zeroes. 我试图将对Vec (切片)的不可变引用传递给一个函数,该函数将用递增的值填充Vec ,然后对其进行迭代,再次将其替换为零。

My thinking is that the vector is immutable (the data types and size of the vector will never change) but the contents of the vector should be mutable references to integers. 我的想法是向量是不可变的(向量的数据类型和大小永远不会改变),但是向量的内容应该是对整数的可变引用。 Or should they be the actual values of the integers themselves (and not references)? 还是它们应该是整数本身(而不是引用)的实际值?

This have proven a difficult task.. I've read about mutability and borrowing, and I feel I have an OK understanding of this. 事实证明,这是一项艰巨的任务。.我已经阅读了有关可变性和借用的知识,并且我对此感到很了解。 I also have a cursory understanding of how referencing, dereferencing, pointers, etc. work in C, but I think I am struggling with the syntax of Rust to achieve this. 我对C中的引用,解引用,指针等如何工作有一个粗略的了解,但是我认为我在Rust的语法中苦苦挣扎来实现这一点。

Am I thinking about this the wrong way? 我在想这个错误的方式吗? In Rust, is it more idiomatic to create a copy of a potentially huge Vec , operate on that, and return it? 在Rust中,创建潜在的巨大Vec的副本,对其进行操作并返回它是否更加惯用?

This is my code so far (does not compile, many errors): 到目前为止,这是我的代码(无法编译,有很多错误):

#![feature(iterator_step_by)]

pub fn nth(n: usize) {
    let size: usize = (2 as f64 * n as f64 * (n as f64).ln()) as usize;
    // Set an upper bound for seiving.
    let size_sqrt: usize = (size as f64).sqrt().ceil() as usize;
    let nums: Vec<&mut usize> = Vec::with_capacity(size);
    sieve(nums, &size, &size_sqrt);
}

fn sieve(nums: [&mut usize], size: &usize, size_sqrt: &usize) {
    for i in 0..*size {
        nums[i] = i;
    }
    for num in nums {
        if num < 2 {
            continue;
        } else if num > *size_sqrt {
            break;
        }
        for x in (num.pow(2)..size).step_by(*num) {
            nums[x] = 0;
        }
    }
}

My thinking is that the vector is immutable (the data types and size of the vector will never change) but the contents of the vector should be mutable references to integers. 我的想法是向量是不可变的(向量的数据类型和大小永远不会改变),但是向量的内容应该是对整数的可变引用。 Or should they be the actual values of the integers themselves (and not references)? 还是它们应该是整数本身(而不是引用)的实际值?

References ( &'a T and &'a mut T ) can only refer to values that are owned by another value. 引用( &'a T&'a mut T )只能引用另一个值拥有的值。 References cannot own their referent. 引用不能拥有其引用对象。

It might be a good idea to build a vector of references to integers if you want to have a function that operates on some integers of a collection that are not necessarily contiguous. 如果要具有对集合中某些不一定是连续的整数进行运算的函数,则构建一个整数引用向量可能是一个好主意。 However, based on your code sample, that does not appear to be the case; 但是,根据您的代码示例,情况似乎并非如此。 it will be much simpler and much easier for the vector to own the integers. 向量拥有整数将变得更加容易和容易。 That means that the vector itself will need to be mutable. 这意味着向量本身将需要是可变的。 However, if you want to ensure that a function doesn't try to change the size of a vector, that function can accept a mutable slice of integers &mut [usize] , rather than a mutable reference to the vector ( &mut Vec<usize> ). 但是,如果要确保函数不尝试更改向量的大小,则该函数可以接受可变的整数切片&mut [usize] ,而不是对向量的可变引用( &mut Vec<usize> )。

In Rust, is it more idiomatic to create a copy of a potentially huge Vec , operate on that, and return it? 在Rust中,创建潜在的巨大Vec的副本,对其进行操作并返回它是否更加惯用?

It depends on whether you need to use the original Vec again afterwards. 这取决于之后是否需要再次使用原始Vec If you don't, then it's more efficient to mutate the Vec in-place. 如果您不这样做,那么就地对Vec进行突变会更有效。 If you only need to keep the original Vec in some cases and not in others, you can always clone() the Vec beforehand. 如果在某些情况下只需要保留原始Vec ,而在其他情况下则不需要,则可以始终预先clone() Vec If you do need the original Vec every time, then it may be more efficient to return a new Vec , especially if you can fill it from an iterator using collect , since that will try to allocate the right size ahead of time and only assign each value in the Vec once. 如果确实每次都需要原始Vec ,则返回新Vec可能会更有效,特别是如果您可以使用collect从迭代器填充它,因为这将尝试提前分配正确的大小并仅分配每个Vec Vec值一次。


Considering all this, here's how I would write your code. 考虑到所有这些,这就是我编写代码的方式。 Notice that I had to change the main loop in sieve to not directly iterate over nums , because that lead to a borrow conflict – the for loop needed a borrow on nums , but the assignment nums[x] would also try to take a mutable borrow on nums while the other borrow is active. 请注意,我不得不改变主sieve的主循环,以使其不直接遍历nums ,因为这会导致借入冲突– for循环需要对nums进行借入,但是赋值nums[x]也将尝试进行可变借入nums而其他借项处于活动状态。 I also changed the &usize parameters to usize , because there is no benefit to using references for small, copyable types such as primitive integers (in fact, it may be slightly slower). 我还将&usize参数更改为usize ,因为对小型可复制类型(例如原始整数)使用引用没有任何好处(实际上,它可能会稍慢一些)。

#![feature(iterator_step_by)]

pub fn nth(n: usize) {
    let size: usize = (2.0 * n as f64 * (n as f64).ln()) as usize;
    // Set an upper bound for seiving.
    let size_sqrt: usize = (size as f64).sqrt().ceil() as usize;
    let mut nums: Vec<usize> = vec![0; size];
    sieve(&mut nums, size, size_sqrt);
}

fn sieve(nums: &mut [usize], size: usize, size_sqrt: usize) {
    for i in 0..size {
        nums[i] = i;
    }

    for i in 0..size {
        let num = nums[i];
        if num < 2 {
            continue;
        }

        if num > size_sqrt {
            break;
        }

        for x in (num.pow(2)..size).step_by(num) {
            nums[x] = 0;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM