'implicit' 在 Scala 中没有像想象的那样工作
'implicit' in Scala not working as thought
为了理解 'implicit' 在 Scala 中的工作原理,我编写了以下代码,但它没有给我预期的结果。
我以为我理解 'implicit' 的用法(这显然不是真的)。我有三个 classes,Plant、Dog 和 myPet。 Dog 有一个函数 'sound' 其中 returns "woof"。 Plant 有一个函数 "tallOrShort" 其中 returns "tall"。这些函数描述了 Dog and Plant 的特征。
我想在 myPet 中编写一个通用代码,我可以将 Dog 或 Plant 的实例传递给它。我称这个函数为'describe'。 describe 函数应该为 Dog 实例打印 "woof",为 Plant 实例打印 "tall"。
狗和植物是独立的 classes(无子类型)。我想我可以在 Dog and Plant class 中使用 'implicit' 到 "add" 这个功能。我的理解是,通过使用隐式,可以将 Dog 或 Plant 隐式转换为 'something',然后可以分别为 Dog 和 Plant 调用 'sound' 或 'tallOrShort'。我写了下面的代码,但它不起作用。
我从 Dog class 开始
//create Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//create trait (the contract interface which Dog can be member of
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//implicit conversion should happen using this code?
scala> implicit object dogIsPet extends myPetTrait[Dog] {
| def describePet(d:Dog) = d.sound
| }
defined object dogIsPet
现在首先,我想按如下方式只定义一个通用函数 'describe',但我无法将 Dog 或 Plant 实例传递给它。
//'describe' function. It should work for both Dog and Plant
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
问题 1 - 以上有什么问题? Dog 不应该转换为 myPetTrait[Dog] 吗?
然后我想创建一个class(myPet)并在class中定义'describe'。那也不行
//metPet It should work for both Dog and Plant
scala> class myPet[A](a:A) {
| def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
| }
defined class myPet
scala> new myPet(new Dog).describe
<function1>
问题 2 - 如果我将 describe 放在 myPet 中,为什么至少可以编译?为什么我得到的是函数文字 (function1),而不是我期望的打印结果
为了继续试验,我再次启动了 REPL,并在创建 describe 和 myPet 之前声明了 Plant
//new REPL session. created Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//created plant
scala> class Plant {
| def tallOrShort = "tall"
| }
defined class Plant
//created trait
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//code which should I think help in implicit conversion
scala> implicit object plantIsPet extends myPetTrait[Plant] {
| def describePet(p:Plant) = p.tallOrShort
| }
defined object plantIsPet
//describe still doesn't work
//describe shuold work for both Plant and Animal
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
//not sure why this error comes
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
//get ambiguity error in this line
scala> new myPet(new Dog).describe //myPet gives ambiguity error
我收到不明确的隐式值错误,指出类型 dogIsPet.type 的对象 dogIsPet 和类型 plantIsPet.type 的对象 plantIsPet 都匹配预期类型 myPetTrait[A]
问题 3 - 为什么 Scala 会抱怨歧义?这可能是因为 dogIsPet.type 和 plantisPet.type 是相同的 'type'。我如何使这段代码起作用?
我想你错过了这个(describe
必须采用 a
类型 A
和 implicit
合同)
在myPet
中像这样定义describe
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
在myPet
之外的describe
可以这样声明
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
Scala 对此有特殊的语法
def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
Scala REPL
scala> def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
describe: [A](a: A)(implicit pt: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
或者使用scala语法糖
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
describe: [A](a: A)(implicit evidence: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
scala> trait myPetTrait[A] { def describePet(a:A):String }
defined trait myPetTrait
scala> class Dog { def sound = "woof" }
defined class Dog
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
defined function describe
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> describe[Dog](new Dog)
woof
scala> class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
defined class myPet
scala> new myPet[Dog](new Dog).describe
woof
一处完整代码
Main.scala
object Implicits {
trait myPetTrait[A] {
def describePet(a:A):String
}
class Dog {
def sound = "woof"
}
class Plant {
def tallOrShort = "tall"
}
//evidence for Plant
implicit object plantIsPet extends myPetTrait[Plant] {
def describePet(p:Plant) = p.tallOrShort
}
//evidence for Dog
implicit object dogIsPet extends myPetTrait[Dog] {
def describePet(d:Dog) = d.sound
}
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
//syntactic sugar
def describe2[A : myPetTrait](a: A) =
println(implicitly[myPetTrait[A]].describePet(a))
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
}
object Main {
import Implicits._
def main(args: Array[String]): Unit = {
describe(new Dog)
describe(new Plant)
describe2(new Dog)
describe2(new Plant)
new myPet[Dog](new Dog).describe
new myPet[Plant](new Plant).describe
}
}
输出:
woof
tall
woof
tall
woof
tall
为了理解 'implicit' 在 Scala 中的工作原理,我编写了以下代码,但它没有给我预期的结果。
我以为我理解 'implicit' 的用法(这显然不是真的)。我有三个 classes,Plant、Dog 和 myPet。 Dog 有一个函数 'sound' 其中 returns "woof"。 Plant 有一个函数 "tallOrShort" 其中 returns "tall"。这些函数描述了 Dog and Plant 的特征。
我想在 myPet 中编写一个通用代码,我可以将 Dog 或 Plant 的实例传递给它。我称这个函数为'describe'。 describe 函数应该为 Dog 实例打印 "woof",为 Plant 实例打印 "tall"。
狗和植物是独立的 classes(无子类型)。我想我可以在 Dog and Plant class 中使用 'implicit' 到 "add" 这个功能。我的理解是,通过使用隐式,可以将 Dog 或 Plant 隐式转换为 'something',然后可以分别为 Dog 和 Plant 调用 'sound' 或 'tallOrShort'。我写了下面的代码,但它不起作用。
我从 Dog class 开始
//create Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//create trait (the contract interface which Dog can be member of
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//implicit conversion should happen using this code?
scala> implicit object dogIsPet extends myPetTrait[Dog] {
| def describePet(d:Dog) = d.sound
| }
defined object dogIsPet
现在首先,我想按如下方式只定义一个通用函数 'describe',但我无法将 Dog 或 Plant 实例传递给它。
//'describe' function. It should work for both Dog and Plant
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
问题 1 - 以上有什么问题? Dog 不应该转换为 myPetTrait[Dog] 吗?
然后我想创建一个class(myPet)并在class中定义'describe'。那也不行
//metPet It should work for both Dog and Plant
scala> class myPet[A](a:A) {
| def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
| }
defined class myPet
scala> new myPet(new Dog).describe
<function1>
问题 2 - 如果我将 describe 放在 myPet 中,为什么至少可以编译?为什么我得到的是函数文字 (function1),而不是我期望的打印结果
为了继续试验,我再次启动了 REPL,并在创建 describe 和 myPet 之前声明了 Plant
//new REPL session. created Dog
scala> class Dog {
| def sound = "woof"
| }
defined class Dog
//created plant
scala> class Plant {
| def tallOrShort = "tall"
| }
defined class Plant
//created trait
scala> trait myPetTrait[A] {
| def describePet(a:A):String
| }
defined trait myPetTrait
//code which should I think help in implicit conversion
scala> implicit object plantIsPet extends myPetTrait[Plant] {
| def describePet(p:Plant) = p.tallOrShort
| }
defined object plantIsPet
//describe still doesn't work
//describe shuold work for both Plant and Animal
scala> def describe[A](implicit pt:myPetTrait[A]) = {println(pt.describePet(_:A))}
describe: [A](implicit pt: myPetTrait[A])Unit
//not sure why this error comes
scala> describe(new Dog)
<console>:21: error: type mismatch;
found : Dog
required: myPetTrait[?]
describe(new Dog)
//get ambiguity error in this line
scala> new myPet(new Dog).describe //myPet gives ambiguity error
我收到不明确的隐式值错误,指出类型 dogIsPet.type 的对象 dogIsPet 和类型 plantIsPet.type 的对象 plantIsPet 都匹配预期类型 myPetTrait[A]
问题 3 - 为什么 Scala 会抱怨歧义?这可能是因为 dogIsPet.type 和 plantisPet.type 是相同的 'type'。我如何使这段代码起作用?
我想你错过了这个(describe
必须采用 a
类型 A
和 implicit
合同)
在myPet
describe
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
在myPet
之外的describe
可以这样声明
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
Scala 对此有特殊的语法
def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
Scala REPL
scala> def describe[A](a: A)(implicit pt:myPetTrait[A]) = {println(pt.describePet(a))}
describe: [A](a: A)(implicit pt: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
或者使用scala语法糖
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
describe: [A](a: A)(implicit evidence: myPetTrait[A])Unit
scala> describe[Plant](new Plant)
tall
scala> trait myPetTrait[A] { def describePet(a:A):String }
defined trait myPetTrait
scala> class Dog { def sound = "woof" }
defined class Dog
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> def describe[A: myPetTrait](a: A) = println(implicitly[myPetTrait[A]].describePet(a))
defined function describe
scala> implicit object dogIsPet extends myPetTrait[Dog] { def describePet(d:Dog) = d.sound }
defined object dogIsPet
scala> describe[Dog](new Dog)
woof
scala> class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
defined class myPet
scala> new myPet[Dog](new Dog).describe
woof
一处完整代码
Main.scala
object Implicits {
trait myPetTrait[A] {
def describePet(a:A):String
}
class Dog {
def sound = "woof"
}
class Plant {
def tallOrShort = "tall"
}
//evidence for Plant
implicit object plantIsPet extends myPetTrait[Plant] {
def describePet(p:Plant) = p.tallOrShort
}
//evidence for Dog
implicit object dogIsPet extends myPetTrait[Dog] {
def describePet(d:Dog) = d.sound
}
def describe[A](a: A)(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
//syntactic sugar
def describe2[A : myPetTrait](a: A) =
println(implicitly[myPetTrait[A]].describePet(a))
class myPet[A](a:A) {
def describe(implicit pt:myPetTrait[A]) = {
println(pt.describePet(a))
}
}
}
object Main {
import Implicits._
def main(args: Array[String]): Unit = {
describe(new Dog)
describe(new Plant)
describe2(new Dog)
describe2(new Plant)
new myPet[Dog](new Dog).describe
new myPet[Plant](new Plant).describe
}
}
输出:
woof
tall
woof
tall
woof
tall