闭包作为Rust结构中的一种类型 [英] Closures as a type in a Rust struct

查看:85
本文介绍了闭包作为Rust结构中的一种类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Rust中创建这样的结构:

I am trying to create a struct like this in Rust:

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

我的构造函数如下:

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

但是,当尝试实例化类时,使用 let a = Struct ::< MyEnum> :: new(MyEnum :: Init ); ,编译器抱怨泛型需要两个参数(期望2个类型参数,找到1

However when trying to instantiate the class, using let a = Struct::<MyEnum>::new(MyEnum::Init);, the compiler complains that the generics needs two arguments (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 没有任何参数,取决于 F ,因此编译器无法推断 F 应该使用哪种类型。如果以后调用使用 F 的方法,则编译器将使用该信息来找出 Struct 的具体类型。例如:

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. If you called a method later that used F, then the compiler would use that information to figure out the Struct's concrete type. 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`
}

提供类型这个。如果我们第二次调用 set_fn 并使用不同的闭包:

There's a problem with this though. If we call set_fn a second time with a different closure:

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);
   |                 ^^^^

如编译器所提到的,每个闭包表达式定义一个全新的类型并计算为这种类型。但是,通过按您的方式定义 Struct ,您将迫使 HashMap 中的所有函数都具有相同的类型。

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. Is that really what you want?

如果您想将 T 的不同值映射到可能不同的闭包,那么您将需要使用特征对象而不是泛型,如编译器建议的那样。如果要让该结构拥有闭包,则必须在对象类型周围使用 Box

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. If you want the struct to own the closure, then you'll have to use a Box around the object type.

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

set_fn 可能看起来像这样:

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

这篇关于闭包作为Rust结构中的一种类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆