在Scala中调用通用类型的“静态函数”

Jak*_*erg 2 generics scala

我试图用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 + "[]"
  }
}
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是获取一个元素underlying并对其进行调用typeName,但是如果Seq[T]Nil呢?

我的第二个想法是为所有扩展类创建一个0参数构造函数MyType,以便可以调用,new T().typeName但这似乎并不麻烦,并且没有办法强制类型的所有子类型包含具有特定签名的构造函数。

在这里,我找到了清单和TypeTag。我看到了它们与我的问题的关系,但是看不到它们如何帮助我构建解决方案!

Dim*_*ima 5

这种事情通常是通过类型类来完成的:

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 + "[]"
}
Run Code Online (Sandbox Code Playgroud)

这个想法是,无论何时MyContainerClass创建,TypeName都会查找的对应实例并将其隐式传递给构造函数,因此您可以在那里访问它并检索名称。