我一直在研究无形单体的细节,并遇到了一个不能按预期工作的小例子。我认为只要我们将单例类型传递给方法,就应该有一个隐含的Witness.Aux [_]在范围内可用:
import shapeless._
import syntax.singleton._
object SingletonTest extends App {
def check[K](a: K)(implicit witness: Witness.Aux[K]): Unit = {
println(witness.value)
}
val b = 'key.narrow
val c: Witness.`'key`.T = b
check(c) // Works!
check(b) /* Fails: shapeless.this.Witness.apply is not a valid implicit value for shapeless.Witness.Aux[Symbol with shapeless.tag.Tagged[String("key")]] because:
hasMatchingSymbol reported error: Type argument Symbol with shapeless.tag.Tagged[String("key")] is not a singleton type */
}
我希望示例中的b和c的类型相同(并使用=:= success)进行检查。如果我手动将隐式Witness [Witness。'key
。T]添加到范围中,代码就会编译。
环境:Scala 2.11.8;无形2.3.0
答案 0 :(得分:4)
解释是,在推断左侧val的类型时,Scala编译器将在右侧扩展单例类型...您将在Scala语言的the relevant section中找到章节和经文说明书
这是一个独立于无形状的相同现象的例子,
scala> class Foo ; val foo = new Foo
defined class Foo
foo: Foo = Foo@8bd1b6a
scala> val f1 = foo
f1: Foo = Foo@8bd1b6a
scala> val f2: foo.type = foo
f2: foo.type = Foo@8bd1b6a
从f2
的定义可以看出,Scala编译器知道值foo
具有更精确的类型foo.type
(即val foo
的单例类型但是,除非明确要求,否则不会推断出更精确的类型。相反,它可以推断非单例(即加宽)类型Foo
,如f1
中所示。