简体   繁体   中英

Generic traits with companion object

I am using scala 2.10. I am still (very) new to scala and I am not able to understand why I cant access name field of Person case class inside the print method of trait Printer[T] .

This is the sample code: it prints out 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
}

If you put no constraints to T, that is, say some requirements about it, you cannot 'know' that you can call any specific method (except toString, hashCode, equals and some more methods that exists on all objects).

One way you could do that is by not using a generic like you do at all, but instead be specific:

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

Or you could use a type bound for your T that expresses a requirement for what T is allowed to be:

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

This way you can only create implementations of Printer where the concrete type you put in implements the Printable trait.

I guess this would compile:

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)
  }
}

or using structural typing:

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)
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM