J'essaie de calculer le 10 001e premier dans Rust (Project Euler 7), et dans le cadre de cela, ma méthode pour vérifier si un entier est premier fait référence à un vecteur:
fn main() {
let mut count: u32 = 1;
let mut num: u64 = 1;
let mut primes: Vec<u64> = Vec::new();
primes.Push(2);
while count < 10001 {
num += 2;
if vectorIsPrime(num, primes) {
count += 1;
primes.Push(num);
}
}
}
fn vectorIsPrime(num: u64, p: Vec<u64>) -> bool {
for i in p {
if num > i && num % i != 0 {
return false;
}
}
true
}
Lorsque j'essaie de référencer le vecteur, j'obtiens l'erreur suivante:
error[E0382]: use of moved value: `primes`
--> src/main.rs:9:31
|
9 | if vectorIsPrime(num, primes) {
| ^^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because `primes` has type `std::vec::Vec<u64>`, which does not implement the `Copy` trait
Que dois-je faire pour primes
afin de pouvoir y accéder dans la fonction vectorIsPrime
?
Avec la définition actuelle de votre fonction vectorIsPrime()
, la fonction spécifie qu'elle requiert la propriété du paramètre car vous le passez par valeur .
Lorsqu'une fonction requiert un paramètre par valeur, le compilateur vérifie si la valeur peut être copiée en vérifiant si elle implémente le trait Copy
.
C'est la signification du message d'erreur que vous avez.
Cependant, la plupart des fonctions ne nécessitent pas la propriété des paramètres: elles peuvent travailler sur des "références empruntées", ce qui signifie qu'elles ne possèdent pas réellement la valeur (et ne peuvent pas par exemple la mettre dans un conteneur ou la détruire).
fn main() {
let mut count: u32 = 1;
let mut num: u64 = 1;
let mut primes: Vec<u64> = Vec::new();
primes.Push(2);
while count < 10001 {
num += 2;
if vector_is_prime(num, &primes) {
count += 1;
primes.Push(num);
}
}
}
fn vector_is_prime(num: u64, p: &[u64]) -> bool {
for &i in p {
if num > i && num % i != 0 {
return false;
}
}
true
}
La fonction vector_is_prime()
spécifie maintenant qu'elle n'a besoin que d'une tranche , c'est-à-dire un pointeur emprunté vers un tableau (y compris sa taille) que vous peut obtenir à partir d'un vecteur en utilisant l'opérateur d'emprunt &
.
Pour plus d'informations sur la propriété, je vous invite à lire la partie du livre traitant de propriété .
La rouille est, comme je dirais, un langage "axé sur les valeurs". Cela signifie que si vous définissez des nombres premiers comme celui-ci
let primes: Vec<u64> = …
ce n'est pas une référence à un vecteur. C'est pratiquement une variable qui stocke une valeur de type Vec<u64>
Comme toute variable u64
Stocke une valeur u64
. Cela signifie que si vous le passez à une fonction définie comme ceci
fn vec_is_prime(num: u64, vec: Vec<u64>) -> bool { … }
la fonction obtiendra sa propre valeur u64
et sa propre valeur Vec<u64>
.
La différence entre u64
Et Vec<u64>
Est cependant qu'une valeur u64
Peut être facilement copiée vers un autre endroit alors qu'une valeur Vec<u64>
Ne peut que déplacer vers un autre endroit facilement. Si vous voulez donner à la fonction vec_is_prime
Sa propre valeur Vec<u64>
Tout en en gardant une pour vous-même, vous devez la dupliquer d'une manière ou d'une autre. C'est à cela que sert clone()
. La raison pour laquelle vous devez être explicite ici est que cette opération n'est pas bon marché. C'est une bonne chose à propos de Rust: il n'est pas difficile de repérer des opérations coûteuses. Donc, vous pourriez appeler la fonction comme ceci
if vec_is_prime(num, primes.clone()) { …
mais ce n'est pas vraiment ce que vous voulez, en fait. La fonction n'a pas besoin de sa propre valeur Vec<64>
. Il a juste besoin de l'emprunter pour une courte période. L'emprunt est beaucoup plus efficace et applicable dans ce cas:
fn vec_is_prime(num: u64, vec: &Vec<u64>) -> bool { …
L'invoquer nécessite désormais "l'opérateur emprunteur":
if vec_is_prime(num, &primes) { …
Bien mieux. Mais nous pouvons encore l'améliorer. Si une fonction veut emprunter un Vec<T>
Juste pour le lire, il vaut mieux prendre un &[T]
À la place:
fn vec_is_prime(num: u64, vec: &[u64]) -> bool { …
C'est juste plus général. Maintenant, vous pouvez prêter une certaine partie d'un Vec à la fonction ou à quelque chose d'autre (pas nécessairement un Vec
, tant que ce quelque chose stocke ses valeurs consécutivement en mémoire, comme une table de recherche statique). Ce qui est aussi bien, c'est qu'en raison des règles de conversion, vous n'avez rien à modifier sur le site de l'appel. Vous pouvez toujours appeler cette fonction avec &primes
Comme argument.
Pour String
et &str
La situation est la même. String
sert à stocker des valeurs de chaîne dans le sens où une variable de ce type possède cette valeur. &str
Sert à les emprunter.
Vous déplacez la valeur de primes
vers la fonction vectorIsPrime
(BTW Rust use snake_case
par convention). Vous avez d'autres options, mais la meilleure consiste à emprunter un vecteur au lieu de le déplacer:
fn vector_is_prime(num: u64, p: &Vec<u64>) -> bool { … }
Et puis en passant la référence:
vector_is_prime(num, &primes)