Trait 中 first parameter of method _ is not Self 相关需求问题

还是 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 个赞

确实, 看了下之前 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 }
}

似乎不大通用办法. 但想了想 RespoApp 本身结构确实也是固定, 是可以用这样的写法简化一些. 感谢.