使用类型类隐式转换为超类型

Ref*_*fer 1 scala typeclass implicit-cast implicit-conversion

为什么foo1失败而foo2成功?编译器不应该自动检查Blah的所有超类型吗?

trait Foo[A] {
  def bar: A
}

trait Bleh;
case class Blah extends Bleh;
implicit object BlehFoo extends Foo[Bleh]

def foo1[A:Foo](a:A) = a

def foo2[A,B:Foo](a:A)(implicit aToB: A => B) = aToB(a)

// Shouldn't it automatically use Bleh?
foo1(Blah())
// Failure: could not find implicit value for evidence parameter of type Foo[Blah]

foo2(Blah())
// Success: Bleh = Blah()
Run Code Online (Sandbox Code Playgroud)

sen*_*nia 6

不能使用Foo[Bleh]作为Foo[Blah],因为Foo[Bleh]不是Foo[Blah].您应该Foo对逆变A使用Foo[Bleh]Foo[Blah].

trait Foo[-A] {
  def bar(a: A) = println(a) // to make Foo contravariant 
}
Run Code Online (Sandbox Code Playgroud)

这很好用:

scala> foo1(Blah())
res0: Blah = Blah()
Run Code Online (Sandbox Code Playgroud)

您的原始代码包含您问题的答案.让我们假设你可以使用你原来Foo[Bleh]Foo[Blah]:

def foo1[A:Foo](): A = implicitly[Foo[A]].bar

val b: Blah = foo1[Blah]()
Run Code Online (Sandbox Code Playgroud)

如果在Foo[Bleh]这里使用你将得到Bleh结果bar,但你期待Blah,Bleh而不是一个Blah.

幸运的是,编译器不允许您将原始文件Foo[Bleh]用作Foo[Blah]:

scala> trait Foo[-A] {
     |   def bar: A
     | }
<console>:8: error: contravariant type A occurs in covariant position in type => A of method bar
         def bar: A
             ^
Run Code Online (Sandbox Code Playgroud)

类型推断

这很好用:

foo1[Bleh](Blah())
Run Code Online (Sandbox Code Playgroud)

但编译器不会A在此推断类型参数Bleh.为了理解"为什么"我们应该知道什么A:Foo意思:

def foo1[A:Foo](a:A) = a // syntax sugar
def foo1[A](a:A)(implicit ev: Foo[A]) = a // same method
Run Code Online (Sandbox Code Playgroud)

A:Foo 是一个加法隐式参数的语法糖.

如果您有2个参数组,编译器将推断第一组中的类型,然后将该类型视为已知类型.因此,对第一个参数组(a:A)类型的类型推断Blah已知并且第二个参数组不会影响类型参数.