Scala: «неявно» и параметр типа - PullRequest
0 голосов
/ 21 мая 2011

У меня возникли небольшие проблемы с пониманием следующего явления:

trait Trait[A] {
  def traitType: String
}

object Trait {
  implicit val stringTrait: Trait[String] = new Trait[String] {
    def traitType: String = "string"
  }

  implicit val intTrait: Trait[Int] = new Trait[Int] {
    def traitType: String = "int"
  }
}

class Media[A] {
  // works
  def mediaType(implicit t: Trait[A]): String = t.traitType
  // does not compile
  def mediaType: String = implicitly[Trait[A]].traitType
}

object Main {
  def main(args: Array[String]) {
    val a = new Media[String]
    val b = new Media[Int]

    println(a.mediaType)
    println(b.mediaType)
  }
}

В приведенном выше фрагменте я показываю 2 разные реализации метода mediaType (я комментирую одну из нихпри компиляции кода).Однако версия, использующая неявно , не компилируется?Я получаю следующее сообщение об ошибке:

impl.scala:19: error: could not find implicit value for parameter e: Trait[A]
  def mediaType: String = implicitly[Trait[A]].traitType
                                    ^
one error found

Я понимаю, что не существует неявного значения Trait [A].Я не понимаю, почему A не разрешается в тип, с которым создается экземпляр Media.Я думаю, что слишком много думаю о шаблонах C ++ здесь, и я был бы очень признателен, если бы кто-то мог дать мне указатель в правильном направлении.

С уважением, raichoo

Ответы [ 2 ]

9 голосов
/ 21 мая 2011

Компилятору нужны доказательства того, что существует неявный Trait экземпляр для A. В первой реализации mediaType вы объявляете это требование. Но во второй реализации, с точки зрения компилятора, такой гарантии нет. Поэтому, чтобы заставить его работать, вы должны попросить пользователей класса Media предоставить его. Вы можете сделать это с привязкой к контексту:

class Media[A : Trait] {
  def mediaType: String = implicitly[Trait[A]].traitType
}

Это также можно записать более явно:

class Media[A](implicit val evidence: Trait[A]) {
  def mediaType: String = implicitly[Trait[A]].traitType
}

Таким образом, другими словами, конструктор по умолчанию требует неявного evidence, и пользователи не смогут создать экземпляр класса Media, не предоставив его (явно или неявно).

2 голосов
/ 21 мая 2011

Если вы хотите, чтобы эта версия компилировалась:

def mediaType: String = implicitly[Trait[A]].traitType

тогда неявный экземпляр Trait[A] должен быть передан, например, когда создается новый экземпляр Media. Попробуйте определить Media следующим образом:

class Media[A](implicit private val t: Trait[A]) {
  def mediaType: String = t.traitType
}

Почти эквивалентное определение, использующее привязанный к контексту , это:

class Media[A: Trait] {
  def mediaType: String = implicitly[Trait[A]].traitType
}

При этом, если вы пытаетесь сохранить больше информации о параметре типа параметризованного типа, вы можете использовать Manifest s вместо своего собственного механизма. Они предоставят вам полную информацию о типе A во время выполнения, в том числе, если A сам по себе является параметризованным типом:

scala> class Media[A](implicit val aManifest: Manifest[A])
defined class Media

scala> new Media[Int].aManifest
res0: Manifest[Int] = Int

scala> new Media[Seq[(Int, String)]].aManifest        
res1: Manifest[Seq[(Int, String)]] = scala.collection.Seq[scala.Tuple2[Int, java.lang.String]]
...