2017-03-17 1 views
2
#![feature(unboxed_closures)] 
#![feature(fn_traits)] 

struct foo; 

impl std::ops::Add for foo { 
    type Output = foo; 
    fn add(self, x: foo) -> foo { 
     println!("Add for foo"); 
     x 
    } 
} 

impl Fn for foo { 
    extern "rust-call" fn call(&self) -> Self { 
     println!("Call for Foo "); 
     self 
    } 
} 

fn main() { 
    let x = foo; 
    let y = foo; 
    x + y; 

    x(); 
} 

J'ai implémenté le trait Add, mais je ne comprends pas comment appeler la structure en tant que fonction. J'obtiens l'erreur:Comment créer une structure appelable?

error[E0243]: wrong number of type arguments: expected 1, found 0 
    --> src/main.rs:14:10 
    | 
14 |  impl Fn for foo { 
    |   ^^ expected 1 type argument 

Je suis nouveau à Rust, et je ne trouve pas d'exemples comment faire pour que cela se produise.

Répondre

7

Il est très utile pour de lire complètement le trait que vous implémentez pour voir comment l'implémenter. Le Fn trait est défini comme:

pub trait Fn<Args>: FnMut<Args> { 
    extern "rust-call" fn call(&self, args: Args) -> Self::Output; 
} 

Avis des différences entre la mise en œuvre et la définition? Je vois beaucoup:

  1. La mise en œuvre ne fournit pas de valeur pour Args! C'est ce que le compilateur pointe vers. Voir aussi Wrong number of type arguments: expected 1 but found 0

  2. La mise en œuvre n'implémente pas le supertrait FnMut, ce qui nécessite lui-même le supertrait FnOnce. FnOnce est où le associé typeOutput est déclaré.

  3. La mise en œuvre néglige de définir quel type de béton Output devrait être. L'implémentation renvoie Self alors que l'attribut renvoie Self::Output.

  4. L'implémentation n'accepte pas le second argument à call. Cet argument contient des arguments transmis.

De plus, les types à utiliser Rust PascalCase, pas snake_case, il devrait donc être Foo.

#![feature(unboxed_closures)] 
#![feature(fn_traits)] 

struct Foo; 

impl Fn<()> for Foo { 
    extern "rust-call" fn call(&self, _args:()) { 
     println!("Call (Fn) for Foo"); 
    } 
} 

impl FnMut<()> for Foo { 
    extern "rust-call" fn call_mut(&mut self, _args:()) { 
     println!("Call (FnMut) for Foo"); 
    } 
} 

impl FnOnce<()> for Foo { 
    type Output =(); 

    extern "rust-call" fn call_once(self, _args:()) { 
     println!("Call (FnOnce) for Foo"); 
    } 
} 

fn main() { 
    let x = Foo; 
    x(); 
} 

Normalement cependant, la mise en œuvre qu'un seul trait aurait un code intéressant et les autres implémentations de trait pourrait déléguer:

extern "rust-call" fn call(&self, args:()) { 
    println!("Foo called, took args: {:?}", args); 
} 

// ... 

extern "rust-call" fn call_mut(&mut self, args:()) { 
    self.call(args) 
} 

// ... 

extern "rust-call" fn call_once(self, args:()) { 
    self.call(args) 
} 
+0

Merci beaucoup! Très bonne explication. –

+0

@ АндрейЛедовских vous êtes les bienvenus. Rappelez-vous d'augmenter les réponses utiles et d'accepter la réponse qui vous a le plus aidé à résoudre votre problème. – Shepmaster