Les traits sur des tableaux plus grands
Un trait est un agrégat de méthodes définies pour un type inconnu : Self. Elles peuvent accéder aux autres méthodes déclarées dans le même trait. Les traits peuvent être implémentés pour n'importe quel type de donnée. Dans l'exemple ci-dessous, nous définissons Animal, un groupe de méthodes. Le trait Animal est alors implémenté pour le type Sheep, permettant l'utilisation des méthodes de Animal avec une instance du type Sheep.
Code Rust : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | struct Sheep { naked: bool, name: &'static str } trait Animal { // Méthode statique; `Self` fait référence au type ayant implémenté // le trait. fn new(name: &'static str) -> Self; // Méthode d'instance; Elles renverront une chaîne de caractères. fn name(&self) -> &'static str; fn noise(&self) -> &'static str; // Les traits peuvent fournir une implémentation par défaut. fn talk(&self) { println!("{} says {}", self.name(), self.noise()); } } impl Sheep { fn is_naked(&self) -> bool { self.naked } fn shear(&mut self) { if self.is_naked() { // Les méthodes de `Self` peuvent utiliser les méthodes déclarées // par le trait. println!("{} is already naked...", self.name()); } else { println!("{} gets a haircut!", self.name); self.naked = true; } } } // Implémentation des services du trait `Animal` // pour le type `Sheep`. impl Animal for Sheep { // En l'occurrence, `Self` fait référence à `Sheep`. fn new(name: &'static str) -> Sheep { Sheep { name: name, naked: false } } fn name(&self) -> &'static str { self.name } fn noise(&self) -> &'static str { if self.is_naked() { "baaaaah?" } else { "baaaaah!" } } // L'implémentation par défaut fournie par le trait // peut être réécrite. fn talk(&self) { // Par exemple, nous pourrions fournir une description plus précise. println!("{} pauses briefly... {}", self.name, self.noise()); } } fn main() { // Typer l'identificateur est nécessaire dans ce cas de figure. let mut dolly: Sheep = Animal::new("Dolly"); // TODO ^ Essayez de supprimer le type annoté. dolly.talk(); dolly.shear(); dolly.talk(); } |
Rust n'a actuellement pas de moyen d'être générique sur des valeurs entières. Cela a longtemps posé des problèmes avec les tableaux, car les tableaux ont un entier dans leur type; [T; N] est le type d'un tableau de type T de longueur N. Comme il n'y a aucun moyen d'être générique sur N, vous devez implémenter manuellement des traits pour les tableaux pour chaque N que vous souhaitez prendre en charge. Pour la bibliothèque standard, il a été décidé de prendre en charge une longueur pouvant aller jusqu'à N=32.
L'équipe a travaillé sur une fonctionnalité appelée const generics qui vous permettrait d'être générique sur N. Le cœur de cette fonctionnalité a été implémenté dans le compilateur, et il a été décidé que la fonctionnalité est suffisamment avancée pour que la bibliothèque standard l'utilise pour implémenter des traits sur des tableaux de toute longueur. En pratique, cela signifie que si vous essayez de faire quelque chose comme ça sur Rust 1.46:
Code Rust : | Sélectionner tout |
1 2 3 4 5 | fn main() { let xs = [0; 34]; println!("{:?}", xs); } |
Vous obtiendrez cette erreur :
error[E0277]: arrays only have std trait implementations for lengths 0..=32
--> src/main.rs:4:22
|
4 | println!("{:?}", xs);
| ^^ the trait `std::array::LengthAtMost32` is not implemented for `[{integer}; 34]`
|
= note: required because of the requirements on the impl of `std::fmt::Debug` for `[{integer}; 34]`
= note: required by `std::fmt::Debug::fmt`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
Cela devrait rendre les tableaux beaucoup plus utiles pour les développeurs, bien qu'il faudra attendre que la fonctionnalité const generics soit stabilisée pour que les bibliothèques puissent faire ce type d'implémentation pour leurs propres caractéristiques. L'équipe n'a pas encore arrêté de date à ce sujet.
Des traces plus courtes
Avec Rust 1.18, l'équipe a apporté quelques modifications aux traces que rustc imprimerait en cas de panique (situation obtenue lorsque les programmes Rust atteignent un état où une erreur critique est survenue). Il y a un certain nombre de choses dans une trace qui ne sont pas utiles la plupart du temps. Cependant, à un moment donné, ils ont régressé. Dans Rust 1.47.0, le coupable a été trouvé, et cela a maintenant été corrigé. Depuis la régression, ce programme:
Code Rust : | Sélectionner tout |
1 2 3 | fn main() { panic!(); } |
Produit une trace comme celle-ci :
thread 'main' panicked at 'explicit panic', src/main.rs:2:5
stack backtrace:
0: backtrace::backtrace::libunwind::trace
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/libunwind.rs:86
1: backtrace::backtrace::trace_unsynchronized
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/mod.rs:66
2: std::sys_common::backtrace::_print_fmt
at src/libstd/sys_common/backtrace.rs:78
3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
at src/libstd/sys_common/backtrace.rs:59
4: core::fmt::write
at src/libcore/fmt/mod.rs:1076
5: std::io::Write::write_fmt
at src/libstd/io/mod.rs:1537
6: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:62
7: std::sys_common::backtrace::print
at src/libstd/sys_common/backtrace.rs:49
8: std::panicking::default_hook::{{closure}}
at src/libstd/panicking.rs:198
9: std::panicking::default_hook
at src/libstd/panicking.rs:217
10: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:526
11: std::panicking::begin_panic
at /rustc/04488afe34512aa4c33566eb16d8c912a3ae04f9/src/libstd/panicking.rs:456
12: playground::main
at src/main.rs:2
13: std::rt::lang_start::{{closure}}
at /rustc/04488afe34512aa4c33566eb16d8c912a3ae04f9/src/libstd/rt.rs:67
14: std::rt::lang_start_internal::{{closure}}
at src/libstd/rt.rs:52
15: std::panicking::try::do_call
at src/libstd/panicking.rs:348
16: std::panicking::try
at src/libstd/panicking.rs:325
17: std::panic::catch_unwind
at src/libstd/panic.rs:394
18: std::rt::lang_start_internal
at src/libstd/rt.rs:51
19: std::rt::lang_start
at /rustc/04488afe34512aa4c33566eb16d8c912a3ae04f9/src/libstd/rt.rs:67
20: main
21: __libc_start_main
22: _start
Désormais, dans Rust 1.47.0, vous verrez plutôt ceci :
thread 'main' panicked at 'explicit panic', src/main.rs:2:5
stack backtrace:
0: std::panicking::begin_panic
at /rustc/d6646f64790018719caebeafd352a92adfa1d75a/library/std/src/panicking.rs:497
1: playground::main
at ./src/main.rs:2
2: core::ops::function::FnOnce::call_once
at /rustc/d6646f64790018719caebeafd352a92adfa1d75a/library/core/src/ops/function.rs:227
LLVM 11
Rust 1.47.0 s'accompagne d'une mise à niveau vers LLVM 11. Le compilateur prend toujours en charge la compilation avec des versions de LLVM jusqu'à la version 8. Cependant, par défaut, c'est sur LLVM 11 que vous serez.
Changements dans la bibliothèque
Neuf API sont désormais disponibles en version stable :
- Ident::new_raw
- Range::is_empty
- RangeInclusive::is_empty
- Result::as_deref
- Result::as_deref_mut
- Vec::leak
- pointer::offset_from
- f32::TAU
- f64::TAU
Source : note de version