type de structure anonyme pour le paramètre de fonction
Dans Typescript, je peux faire ceci:
function foo(param: { a: string, b: number }) { }
Afin de déclarer une fonction qui prend dans un objet, sans déclarer explicitement le type de paramètre comme un type nommé comme ceci:
interface Parameter {
a: string;
b: number;
}
function foo(param: Parameter) {}
Existe-t-il un moyen de le faire dans Rust, ou dois-je déclarer explicitement le type de paramètre en tant que type nommé?
Réponses
Rust a une déconstruction de modèle pour les paramètres de fonction sur les tuples, les tableaux et les structures comme ceci:
fn f((a, b): (u32, i32), [x, y, z]: [String; 3]) { }
struct A { a: u32, b: String }
fn g(A { a, b }: A) { }
Mais il n'a pas une telle syntaxe pour les types / objets sans nom, car les objets n'existent tout simplement pas dans rust. Imaginez que rust ait une syntaxe pour cela:
fn f(param: {a: String, b: String}) {} // Invalid code!
Comment quelqu'un appellerait cette fonction? Il n'existe aucun moyen de construire une instance de ce type. En javascript (/ typescript) cela est possible, à cause du typage dynamique, mais dans rust vous devez connaître un type pour pouvoir le construire.
Si vous êtes intéressé par la falsification d'arguments de mots-clés dans les fonctions, cela pourrait aider: Comment optimiser les arguments de fonction de style * faux * mot-clé dans Rust?
Si vous voulez donner un nom aux tuples et avoir un nom pour leurs paramètres, il y a la fonction instable qui bindings_after_at
active cette syntaxe:
#![feature(bindings_after_at)]
fn f(my_tuple @ (a, b): (u32, u32)) {
println!("this: {:?}", my_tuple);
println!("is the same as: {:?}", (a, b));
}
// or this
fn g(arr @ [.., tail] : [u32; 5]) {
println!("this: {}", arr[4]);
println!("is the same as: {}", tail);
}
Vous pouvez utiliser un tuple:
fn foo(param: (String, usize)) {
let a: String = param.0;
let b: usize = param.1;
}
Plutôt que d'avoir des champs nommés comme des structs, les valeurs de tuple sont indexées. La destruction du tuple facilite un peu le suivi des valeurs:
fn foo((a, b): (String, usize)) {
// you can now access `a` and `b` here
}
Vous ne pouvez pas faire de telles choses dans Rust car il a un système de type nominal et votre code est un exemple de systèmes de type structurel. Vous pouvez en savoir plus sur wikipedia:https://en.wikipedia.org/wiki/Nominal_type_system https://en.wikipedia.org/wiki/Structural_type_system
Dans le système de type structurel, le type est juste un ensemble de ses champs et son nom et sa définition n'ont pas d'importance. En revanche, le système de types nominaux traite 2 types avec une déclaration différente mais le même ensemble de champs comme différents (ce qui signifie que le nom du type est plus important que le contenu).
Rust choisi nominal car il est plus stricker et permet d'appliquer certaines propriétés du programme au niveau du type. Prenons cet exemple:
struct Employee(String);
struct Customer(String);
fn handle_order(employee: Employee, customer: Customer){}
Si le programmeur fait une erreur et l'appelle comme ça handle_order(customer, employee)
, c'est une erreur qui ne serait pas remarquée dans un langage avec typage structurel mais qui déclencherait une erreur de compilation dans le typage nominal.
De plus, il peut y avoir une situation où le programmeur doit changer la définition du type, par exemple, ajouter un champ au Employee
. Dans un tel cas, on peut être sûr que la refactorisation est effectuée lorsque toutes les utilisations de l'employé sont fixées. Dans les programmes avec typage structurel, on ne peut pas être sûr car il peut y avoir un code qui envoie le client au lieu de et donc la refactorisation des programmes typés structurels est un peu plus difficile.
Un autre exemple célèbre de saisie nominale dans Rust est la durée de vie . Les variables avec des types avec le même type défini et des durées de vie différentes ont en fait des types nominaux différents. Et toute la sécurité Rusts est basée sur cela.
Typescript utilise le typage structurel car il est plus facile de le mapper en JavaScript.