简体   繁体   中英

Call a “static” method belonging to a generic type in scala

Is there a way in scala to call a method belonging to a type? For example, suppose I have a trait called Constructable that describes types than can construct a default instance of themselves. Then, I can write the following code:

  trait Constructable[A] {
    def construct: A
  }

  class Foo(x: Int) extends Constructable[Foo] {
    def construct = new Foo(0)
  }

  def main(args: Array[String]) {
    val f = new Foo(4)
    println(f.construct)
  }

This is ok, but what I really want is to be able to construct a default object given only the type of object. For example, suppose I want to accept a list of constructables and prepend a default object at the beginning of the list:

  def prependDefault1[A <: Constructable[A]](c: List[A]): List[A] = {
    val h = c.head
    h.construct :: c
  }

The above code works, but only if c is not empty. What I'd really like is to write something like the following:

  def prependDefault2[A <: Constructable[A]](c: List[A]): List[A] = {
    A.construct :: c
  }

Is there any way to achieve this, possibly by changing the definition of a Constructable so that the construct method belongs to the "class" rather than the "instance" (to use Java terminology)?

You can't do this way, but you can do this using typeclasses:

trait Constructable[A] {
  def construct: A
}

// 'case' just so it's printed nicely
case class Foo(x: Int)

// implicit vals have to be inside some object; omitting it here for clarity
implicit val fooConstructable = new Constructable[Foo] {
  def construct = new Foo (0)
}

def prependDefault2[A : Constructable](c: List[A]): List[A] = {
  implicitly[Constructable[A]].construct :: c
}

And then:

scala> prependDefault2(Nil: List[Foo])
res7: List[Foo] = List(Foo(0))

Some final remarks:

Implicits have to live inside an object. There are three places it can be located:

  • object Constructable { implicit val fooConstructable = ... (companion object of the typeclass trait)

  • object Foo { implicit val fooConstructable = ... (companion object of the class we implement typeclass for)

  • object SomethingElse { implicit val fooConstructable = ... (some random unrelated object)

Only in the last case you need to use import SomethingElse._ in order to be able to use the implicit.

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