2017-02-10 3 views
1

J'ai trouvé l'alias de type ci-dessous dans un interpréteur Scheme que j'étudie. Lors de l'évaluation de l'AST, il reconnaît une fonction soit comme une fonction supportée nativement, soit comme une fonction définie par l'utilisateur. Je comprends la deuxième partie de la définition Enum, mais la première partie me échappe.Qu'est-ce qu'une signature et un type de fonction?

pub enum Function { 
    Native(ValueOperation), 
    Scheme(Vec<String>, Vec<Value>, Rc<RefCell<Environment>>), 
} 


type ValueOperation = fn(&[Value], Rc<RefCell<Environment>>) -> Result<Value, RuntimeError>; 

Comment fonctionne ce type d'alias? Est-ce que cette définition indique qu'un ValueOperation est juste un raccourci pour une signature de fonction? Je n'ai pas trouvé de mention de cet idiome dans les docs/livres officiels.

Quel est le but de la définition d'un alias de type pour une signature de fonction? Que pouvez-vous "faire" avec? Est-ce une sorte de pointeur de fonction?

+3

Les alias de type sont expliqués dans la section [Type Aliases du livre] (https://doc.rust-lang.org/book/type-aliases.html); Y at-il quelque chose à propos de ce qui n'est pas clair? –

+0

Oui. A savoir, quel est le but de définir un alias de type pour une signature de fonction? Que pouvez-vous "faire" avec? Est-ce une sorte de pointeur de fonction? – neektza

+0

Ce n'est pas une signature de fonction; c'est un type de pointeur de fonction. 'const X: i32 = 0;' est à 'i32' comme' fn f (i32) -> String {...} 'est' fn (i32) -> String'. C'est un type comme tout autre type. Tout ce que fait est de définir un type de pointeur de fonction avec la signature donnée. Qu'il y ait un alias de type n'est pas pertinent; ça ne change rien. –

Répondre

8

La signature d'une fonction décrit:

  • son nom
  • ses arguments
  • son résultat
  • dans le cas des fonctions génériques, ses paramètres génériques, avec des limites potentiellement spécifiques

Par exemple, si vous définissez:

fn hello(s: &str) { 
    println!("Hello {}", s); 
} 

La signature de la fonction est fn hello(&str).


à Rust, chaque fonction a un type unique de , qui ne peut être nommé. Cependant, si vous avez une fonction, vous pouvez également la contraindre dans un type générique fn qui ne se soucie pas de l'identité de la fonction, mais seulement de la façon dont elle peut être utilisée.

Pour la fonction ci-dessus, ce type générique est: fn(&str) (ou fn(&str) ->() si nous souhaitons être explicites).


Ce type générique est utile pour faire abstraction de plusieurs fonctions avec une signature similaire. Par exemple:

fn add(left: i32, right: i32) -> i32 { left + right } 
fn sub(left: i32, right: i32) -> i32 { left - right } 

fn select(name: &str) -> fn(i32, i32) -> i32 { 
    match name { 
     "add" => add, 
     "sub" => sub, 
     _ => unimplemented!(), 
    } 
} 

fn main() { 
    let fun = select("add"); 
    println!("{} + {} = {}", 1, 2, fun(1, 2)); 
} 

Il est proche de pointeurs de fonction en C ou C++, mais à la différence des pointeurs de fonction ne peut être nulle.

Si vous avez besoin d'une fonction Nullable, vous pouvez utiliser Option<fn(i32, i32) -> i32> à la place.


Et donc finalement nous arrivons à cet alias de type: il est tout simplement un raccourci parce que le type générique fn est longue. Comme tout autre alias de type.

+0

Parfaitement expliqué! TYVM. – neektza

+0

Aussi, par "identité de fonction" je suppose que vous voulez dire le nom de fonction, c'est-à-dire "bonjour"? – neektza

+1

@neektza: Non ... pas vraiment. Dans le cas des fonctions génériques, chaque instance de la fonction générique a sa propre identité, donc c'est un peu plus complexe. –