具有伴随对象的通用特征

Generic traits with companion object

我正在使用 scala 2.10。我对 scala 还是(非常)陌生,我无法理解为什么我无法在 [=4] 的 print 方法中访问 Person case class 的 name 字段=].

这是示例代码: 它打印出来 Person(Mark) Person(Will)

// Model
abstract class BaseModel[T] {
  def all: List[T]
}

case class Person(name: String)
object Person extends BaseModel[Person] {
  val people = Set(Person("Mark"), Person("Will"))
  def all = people.toList.sortBy(_.name)
}

// Controller
trait Printer[T] {
  val model: BaseModel[T]
  def print = model.all.foreach { p =>
    // p.name gives error "value name is not a member of type parameter T"        
    println(p)
  }
}

object PersonPrinter extends Printer[Person] {
    val model = Person
}

// Call
object MyApp extends App {
  PersonPrinter.print
}

如果你对 T 没有任何约束,也就是说,对它提出一些要求,你就不能 'know' 你可以调用任何特定的方法(除了 toString、hashCode、equals 和一些存在于所有对象)。

您可以做到这一点的一种方法是完全不像您那样使用泛型,而是具体化:

trait Printable {
  def text: String
}
trait Printer {
  def model: BaseModel[Printable]
  def print = model.all.foreach(p => println(p.text))
}

或者您可以使用 T 的类型绑定,表达对 T 允许的要求:

trait Printer[T <: Printable] {
  def model: BaseModel[T]
  def print = model.all.foreach(p => println(p.text))
}

这样您只能创建 Printer 的实现,其中您放入的具体类型实现了 Printable 特征。

我猜这会编译:

trait Printer[T<:Person] {
  val model: BaseModel[T]
  def print = model.all.foreach { p =>
    // p.name gives error "value name is not a member of type parameter T"        
    println(p.name)
  }
}

或使用结构类型:

trait Printer[T<: {val name:String}] {
  val model: BaseModel[T]
  def print = model.all.foreach { p =>
    // p.name gives error "value name is not a member of type parameter T"        
    println(p.name)
  }
}