简体   繁体   English

闭包作为Rust结构中的一种类型

[英]Closures as a type in a Rust struct

I am trying to create a struct like this in Rust: 我试图在Rust中创建一个这样的结构:

pub struct Struct<T, F>
    where T: Eq,
          T: Hash,
          F: Fn() -> T
{
    hashMap: HashMap<T, F>,
    value: T,
}

My constructor looks like this: 我的构造函数如下所示:

pub fn new(init_value: T) -> Struct<T, F> {
    Struct {
        hashMap: HashMap::new(),
        value: init_state,
    }
}

However when trying to instantiate the class, using let a = Struct::<MyEnum>::new(MyEnum::Init); 但是,当尝试实例化该类时,请使用let a = Struct::<MyEnum>::new(MyEnum::Init); , the compiler complains that the generics needs two arguments ( expected 2 type arguments, found 1 ) ,编译器抱怨泛型需要两个参数( expected 2 type arguments, found 1

I saw here that this code works: 我在这里看到此代码有效:

fn call_with_one<F>(some_closure: F) -> i32
    where F: Fn(i32) -> i32 {

    some_closure(1)
}

let answer = call_with_one(|x| x + 2);

I guess the problem comes from me having another generic in my template instantiation, but how can I do that? 我猜问题出在我的模板实例化中,我有另一个泛型,但是我该怎么做呢?

Struct::new doesn't have any parameter that depends on F , so the compiler is unable to infer what type it should use for F . Struct::new没有任何依赖于F参数,因此编译器无法推断应为F使用哪种类型。 If you called a method later that used F , then the compiler would use that information to figure out the Struct 's concrete type. 如果稍后调用了一个使用F的方法,则编译器将使用该信息来找出Struct的具体类型。 For example: 例如:

use std::hash::Hash;
use std::collections::HashMap;

pub struct Struct<T, F>
    where T: Eq,
          T: Hash,
          F: Fn() -> T,
{
    hash_map: HashMap<T, F>,
    value: T,
}

impl<T, F> Struct<T, F>
    where T: Eq,
          T: Hash,
          F: Fn() -> T,
{
    pub fn new(init_value: T) -> Struct<T, F> {
        Struct {
            hash_map: HashMap::new(),
            value: init_value,
        }
    }

    pub fn set_fn(&mut self, value: T, func: F) {
        self.hash_map.insert(value, func);
    }
}

fn main() {
    let mut a = Struct::new(0);
    a.set_fn(0, || 1); // the closure here provides the type for `F`
}

There's a problem with this though. 不过有一个问题。 If we call set_fn a second time with a different closure: 如果我们set_fn使用不同的闭包再次调用set_fn

fn main() {
    let mut a = Struct::new(0);
    a.set_fn(0, || 1);
    a.set_fn(1, || 2);
}

then we get a compiler error: 然后我们得到一个编译器错误:

error[E0308]: mismatched types
  --> <anon>:33:17
   |
33 |     a.set_fn(1, || 2);
   |                 ^^^^ expected closure, found a different closure
   |
   = note: expected type `[closure@<anon>:32:17: 32:21]`
   = note:    found type `[closure@<anon>:33:17: 33:21]`
note: no two closures, even if identical, have the same type
  --> <anon>:33:17
   |
33 |     a.set_fn(1, || 2);
   |                 ^^^^
help: consider boxing your closure and/or using it as a trait object
  --> <anon>:33:17
   |
33 |     a.set_fn(1, || 2);
   |                 ^^^^

As mentioned by the compiler, each closure expression defines a brand new type and evaluates to that type. 如编译器所提到的,每个闭包表达式都定义一个全新的类型并对其求值。 However, by defining Struct the way you did, you are forcing all functions in the HashMap to have the same type. 但是,通过按您的方式定义Struct ,您将强制HashMap所有函数都具有相同的类型。 Is that really what you want? 那真的是你想要的吗?

If you want map different values of T to possibly different types of closures, then you'll need to use trait objects instead of generics, as suggested by the compiler. 如果要将不同的T值映射到可能不同的闭包类型,则需要使用trait对象而不是泛型,如编译器建议的那样。 If you want the struct to own the closure, then you'll have to use a Box around the object type. 如果要让该结构拥有闭包,则必须在对象类型周围使用Box

pub struct Struct<T>
    where T: Eq,
          T: Hash,
{
    hash_map: HashMap<T, Box<Fn() -> T + 'static>>,
    value: T,
}

set_fn could then look like this: set_fn可能如下所示:

pub fn set_fn<F: Fn() -> T + 'static>(&mut self, value: T, func: F) {
    self.hash_map.insert(value, Box::new(func));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM