我试图在 Scala 中表示另一种语言的片段。我希望所有类都有一个自定义的 String 值来表示它们的类型。说到容器类,我遇到了麻烦。
我怎样才能抢到 typeName
基于MyContainerClass[T <: MyType]
的泛型参数?
object MyLang {
trait MyType {
protected val typeName: String
}
class MyString(val underlying: String) extends MyType {
protected val typeName = "mystring"
}
class MyInt(val underlying: Int) extends MyType {
protected val typeName = "myint"
}
class MyContainerClass[T <: MyType](val underlying: Seq[T]) extends MyType {
// LINE THAT OBVIOUSLY DOESN'T WORK
val typeName = T.typeName + "[]"
}
}
我的第一个想法是获取
underlying
的元素并调用 typeName
就可以了,但是如果 Seq[T]
是 Nil
?我的第二个想法是为所有扩展
MyType
的类创建一个 0 参数构造函数。 ,以便我可以调用 new T().typeName
但这似乎并不困惑,并且无法强制所有类型的子类型包含具有特定签名的构造函数。从这里我找到了 Manifests 和 TypeTags。我看到它们与我的问题有什么关系,但看不到它们将如何帮助我构建解决方案!
最佳答案
这种事情通常是用类型类来完成的:
trait TypeName[T] {
def typeName: String
}
implicit object MyString extends TypeName[MyString] {
def typeName = "mystring"
}
implicit object MyInt extends TypeName[MyInt] {
def typeName = "myint"
}
class MyString(val underlying: String) extends MyType {
val typeName = MyString.typeName
}
class MyInt(val underlying: Int) extends MyType {
val typeName = MyInt.typeName
}
class MyContainerClass[T <: MyType : TypeName](
val underlying: Seq[T]
) extends MyType {
val typeName = implicitly[TypeName[T]].typeName + "[]"
}
这个想法是,每当
MyContainerClass
被创建,一个对应的实例TypeName
被查找并隐式传递给构造函数,因此您可以在那里访问它并检索名称。
关于scala - 在 Scala 中调用泛型类型的 "static function",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48675692/