Generics Scala:';隐式';和类型参数

Generics Scala:';隐式';和类型参数,generics,scala,type-inference,implicit,Generics,Scala,Type Inference,Implicit,我很难理解以下现象: 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:

我很难理解以下现象:

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)
  }
}
在上面的代码片段中,我展示了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
我知道特质[A]没有隐含的价值。我不明白为什么A不能解析为媒体实例化的类型。我认为我在C++模板上考虑太多了,如果有人能给我一个指向正确的方向的指针,我将非常感激。 问候,,
raichoo

如果要编译此版本:

def mediaType: String = implicitly[Trait[A]].traitType
然后需要传递
Trait[A]
的隐式实例,例如,当创建
Media
的新实例时。请尝试按如下方式定义
媒体

class Media[A](implicit private val t: Trait[A]) {
  def mediaType: String = t.traitType
}
使用a的一个几乎等价的定义是:

class Media[A: Trait] {
  def mediaType: String = implicitly[Trait[A]].traitType
}
这就是说,如果您试图做的是保留关于参数化类型的类型参数的更多信息,那么您可能希望使用而不是您自己的机制。它们将在运行时为您提供有关
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]]

编译器需要证据,证明
A
存在隐式
Trait
实例。在第一个
mediaType
实现中,您声明了此需求。但是在第二个实现中,从编译器的角度来看,没有这样的保证。因此,为了让它发挥作用,你应该要求
媒体
类的用户提供它。您可以使用上下文绑定进行此操作:

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
}

因此,换句话说,默认构造函数需要隐式的
证据
,用户不提供它(显式或隐式)就无法实例化
媒体
类。

上面的代码只是一个示例。我知道清单,谢谢:)@raichoo是的,我只是想避免新用户阅读你的问题,感受到“灵感”,并开始从中派生自己的类似清单的变体…所以类从实例化的隐式上下文中提取Trait[A]值?(与带有隐式参数的mediaType方法相反,该方法将从调用它的上下文中提取值)