接口实现访问问题

pub trait EnumIndex{
  value(Self)->Int
}

pub enum TextAlign{
  Left
  Right
  Center
  Start
  End
}
pub impl EnumIndex for TextAlign with value(self: TextAlign)->Int{
  match self{
    Left=>0
    Right=>1
    Center=>2
    Start=>3
    End=>4    
  }
}

这样实现了接口之后,不能直接使用textAlign.value()来访问这个接口的value方法,必须得用EnumIndex::value(textAlign)来访问?试验了一下,相当于还是得实现一个

pub fn value(self: TextAlign)->Int{
  match self{
    Left=>0
    Right=>1
    Center=>2
    Start=>3
    End=>4    
  }
}

像这种一模一样的方法,才能使用textAlign.value()来访问,这个设计感觉是不是可以稍微优化一下

我印象里用到的时候似乎是有的, 可能需要加上 (textAlign as EnumIndex).value() 才能明确匹配上? 或者某些情况才会自动推断?

这是因为 x.f() 这个语法调用的是普通方法(如果你写 Rust 的话,相当于 impl T { ... }),而 impl 不是普通方法。这两个东西的区别是:

  • 普通方法只能在类型所在的包定义,而 impl 可以在外面定义
  • 同一个类型只能有一个同名方法,但可以 impl 多个不同的、有同名方法的 trait

Rust 是允许用 x.f(...) 调用 impl 的,但这意味着解析 x.f(...) 需要查找所有 import 的包,而且添加一个新的依赖有可能导致现有代码的 x.f(...) 冒出歧义。MoonBit 希望符号解析是一个相对 local 的过程,所以 x.f(...) 只能调用普通方法。

但当你在类型所在的包里 impl 一个 trait 的时候,可能会希望把它自动变成一个方法。这时候可以这么写:

pub fn value(self : TextAlign) -> Int { EnumIndex::TextAlign(self) }
1 个赞

谢谢,用as是可以转换使用了

这样说的话,就大致明白了,如果必须local过程就搞定的话

不过用 as 是有开销的,会分配一个 trait object(Rust 的 dyn)再去调用它。所以如果需要用 .f(...) 调用 impl 还是建议写个 wrapper