tiye
1
还是 Rust 当中迁移过来的代码,
// 不是实际代码...
trait A {
make_from(X1) -> Self
}
trait B {
run(Self, A) -> Unit
}
容易遇到以下的报错, 比如:
The first parameter of method get_action is not `Self`
`Self` occur in the return type of method try_from_string
从字面看, 就是 trait 下的方法限制了需要定义成对应 x.f()
的方式调用.
类似的, Rust 当中 associated type 也有一些场景, Moonbit 似乎没有提供,
// 不是实际代码...
trait C {
type T1
f(Self, T1) -> Unit
}
从 Rust 的体验… 多个 Trait 之间设置约束关系的方式是会挺多样的. 虽然不是强需求, 但某些少数的场景是想着加类似的限制, 目的主要是为了收拢一些模板代码.
想看看有什么办法可以绕过从而实现么?
作为参考的例子还是 Rust, 有一些通用逻辑, 我习惯性想着通过 trait default method 去定义, 然后调用 trait 实例中具体的方法,
trait 本身没有这个限制,但 trait object 有。所以下面这个 trait:
trait A {
make_from(X1) -> Self
}
本身是没问题的。但它不能被用作 trait object(Rust 里的 dyn
),这点 Rust 也是一样的。因为 trait object 必须靠第一个参数来 dispatch。
MoonBit 里直接写 <trait name>
就表示 trait object 类型,相当于 Rust 里的 dyn <trait name>
。这点和 Rust 不一样,Rust 里直接写 <trait name>
是帮你自动生成一个实现了这个 trait 的类型参数。在 MoonBit 里想用普通的多态而非 dynamic dispatch 的话,需要写:
fn f[X : Trait](x : X) ...
1 个赞
tiye
3
确实, 看了下之前 Rust 代码, 还是通过 associated types 绕过去的. 但因为在 MoonBit 里尝试 associated types 不成功, 改写法的时候遇到了前面说的问题. 所以还是有点困惑, 还有其他办法绕么?
也有点不对, 这相当于 trait 上的泛型了吧… 看上去现在没有对应功能
可以用 struct
模拟,比如上面那个 RespoApp
的 trait:
struct RespoApp[Model, Action] {
dispatch : (Model, Action) -> Unit!
pick_storage_key: () -> String
}
fn RespoApp::make[Model, Action](
~dispatch : (Model, Action) -> Unit!,
~pick_storage_key : () -> String = fn () { RESPO_APP_STORE_KEY }
) -> RespoApp[Model, Action] {
{ dispatch, pick_storage_key }
}
tiye
5
似乎不大通用办法. 但想了想 RespoApp 本身结构确实也是固定, 是可以用这样的写法简化一些. 感谢.