递归函数类型 [英] Recursive function type

查看:36
本文介绍了递归函数类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Rob Pike 关于 Go 词法扫描的演讲中,他定义了一个函数类型 stateFn 返回另一个 stateFn,如下所示:

In Rob Pike's talk on lexical scanning in Go, he defines a function type stateFn which returns another stateFn, like so:

type stateFn func() stateFn

为了在 Rust 中做类似的事情,我尝试了这个:

In an attempt to do something similar in Rust, I tried this:

type stateFn = fn() -> stateFn;

但编译器抱怨非法递归类型;如果需要,请在循环中插入枚举或结构".

but the compiler complains "illegal recursive type; insert an enum or struct in the cycle, if this is desired".

我可以在 Rust 中执行此操作吗?如果可以,如何执行?

Can I do this in Rust, and if so, how?

推荐答案

您可以将函数类型包装在名义类型(即结构体或枚举)中.这实际上是 Go 代码所做的:type TU 定义了一个新的、独特的类型 T,它不能与 U 直接互换,而 Rust 的 type 只是一个别名,就像 Haskell 中的 type 和 C 中的 typedef 一样.

You can wrap the function type in a nominal type (i.e. a struct or enum). This is actually what the Go code is doing: type T U defines a new, distinct type T that's not directly interchangable with U, while Rust's type is just an alias, like type in Haskell and typedef in C.

所以,可以这样写:

struct StateFn(fn() -> Option<StateFn>);

struct StateFn {
    f: fn() -> Option<StateFn>
}

(我不得不添加 Option 因为 Go 的 func 可以为 nil,而 Rust 默认删除可空性,使其成为可选.)

(I've had to add the Option because Go's func can be nil, while Rust removes nullability by default, making it opt-in.)

也就是说,我怀疑 func 在 Go 中是一个闭包(可以存储一些内部状态),而在 Rust 中 fn 只是一个函数指针(在all),所以你可能也希望在 Rust 中使用闭包.可以通过替换 fn() ->带有 BoxFn 的选项() -> Option<StateFn>>,并使用 Box::new(move || {/* code here */}) 创建它.

That said, I suspect that func is a closure in Go (can store some internal state), while fn in Rust is just a function pointer (no state at all), so you may wish to use a closure in Rust too. One might do this by replacing fn() -> Option<StateFn> with a Box<Fn() -> Option<StateFn>>, and creating it with Box::new(move || { /* code here */ }).

也可以使用 FnMut 代替Fn 给你更多的灵活性,甚至 FnOnce 表示只能调用一次的闭包.这些中的每一个都对调用者施加了更多的限制,但依次为闭包本身提供了更多的灵活性.(但是,对象安全"问题意味着 Box 目前不起作用,"Purging proc" 有更多细节和解决方法.)

One might also use FnMut instead of Fn which gives you more flexibility, or even FnOnce which represents a closure that can only be called once. Each of these places successively more restrictions on the caller, but gives the closure itself successively more flexibility. (However, "object safety" concerns mean that Box<FnOnce> doesn't work at the moment, "Purging proc" has more details and a work-around.)

struct StateFn {
    f: Box<FnMut() -> Option<StateFn>>
}

任何这些情况的解析循环可能如下所示:

The parsing loop for any of these situations might look like:

let mut state_fn = Some(initial_fn);
while let Some(mut f) = state_fn {
    state_fn = (*f.f)()
}

这篇关于递归函数类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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