我知道很快就会弃用视图边界。请忽略它。
如果最后3个隐式转换中只有一个被取消注释,则以下代码进行编译。这是编译器错误吗?
object Viewable extends App {
/** Speed of light in m/s */
val C: Double = 299293458d
/** @param weight in kilograms */
case class Matter(name: String, weight: Double) {
/** @return matter-energy equivalence in megajoules */
def energy: Double = weight * C * C / 1000000d
def megaJouleMsg: String = f"$name's mass-energy equivalence is $energy%.0f megajoules."
}
case class Animal(name: String, height: Double, weight: Double)
case class Vegetable(name: String, height: Double, weight: Double)
case class Mineral(name: String, weight: Double)
case class Bug(name: String, height: Double, weight: Double, canFly: Boolean)
case class Whale(name: String, height: Double, weight: Double, hasTeeth: Boolean)
case class AppleTree(name: String, height: Double, weight: Double, age: Int)
case class Grass(name: String, height: Double, weight: Double, edible: Boolean)
case class Sand(name: String, color: String, weight: Double)
case class Rock(name: String, color: String, weight: Double)
implicit def sandToMineral(sand: Sand) = Mineral(sand.name, sand.weight)
implicit def rockToMineral(rock: Rock) = Mineral(rock.name, rock.weight)
implicit def appleTreeToVegetable(tree: AppleTree) = Vegetable(tree.name, tree.height, tree.weight)
implicit def grassToVegetable(grass: Grass) = Vegetable(grass.name, grass.height, grass.weight)
implicit def bugToAnimal(bug: Bug) = Animal(bug.name, bug.height, bug.weight)
implicit def whaleToAnimal(whale: Whale) = Animal(whale.name, whale.height, whale.weight)
implicit def animalToMatter[X <% Animal](animal: X) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter[X <% Vegetable](vegetable: X) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter[X <% Mineral](mineral: X) = Matter(mineral.name, mineral.weight)
println(Animal("Poodle", 1.0, 8.0).megaJouleMsg)
println(AppleTree("Spartan", 2.3, 26.2, 12).megaJouleMsg)
println(Rock("Quartz crystal", "white", 2.3).megaJouleMsg)
}
错误消息是:
type mismatch;
found : solutions.Viewable.Animal
required: ?{def megaJouleMsg: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method animalToMatter in object Viewable of type [X](animal: X)(implicit evidence$1: X => solutions.Viewable.Animal)solutions.Viewable.Matter
and method vegetableToMatter in object Viewable of type [X](vegetable: X)(implicit evidence$2: X => solutions.Viewable.Vegetable)solutions.Viewable.Matter
are possible conversion functions from solutions.Viewable.Animal to ?{def megaJouleMsg: ?}
println(Animal("Poodle", 1.0, 8.0).megaJouleMsg)
^
type mismatch;
found : solutions.Viewable.AppleTree
required: ?{def megaJouleMsg: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method animalToMatter in object Viewable of type [X](animal: X)(implicit evidence$1: X => solutions.Viewable.Animal)solutions.Viewable.Matter
and method vegetableToMatter in object Viewable of type [X](vegetable: X)(implicit evidence$2: X => solutions.Viewable.Vegetable)solutions.Viewable.Matter
are possible conversion functions from solutions.Viewable.AppleTree to ?{def megaJouleMsg: ?}
println(AppleTree("Spartan", 2.3, 26.2, 12).megaJouleMsg)
^
答案 0 :(得分:1)
编译器准确地给出了错误。这是因为有多个函数可以Animal => Matter
。即你的3个以下功能:
implicit def animalToMatter[X](animal: X) (implicit ev: X => Animal) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter[X ](vegetable: X) (implicit ev: X => Vegetable) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter[X ](mineral: X) (implicit ev: X => Mineral) = Matter(mineral.name, mineral.weight)
当您执行Animal("Poodle", 1.0, 8.0).megaJouleMsg
时,同样有资格被调用。
当您调用megaJouleMsg
时,编译器会查找任何可用的隐式函数,该函数可以Animal
并返回包含方法megaJouleMsg
(Matter
的对象)。现在所有3个函数都可以使用Animal
(没有任何约束编码),并且可以返回Matter
。因此编译器对调用哪个函数感到困惑
解决方案:从显示的内容来看,不需要视图绑定。这样做:
implicit def animalToMatter(animal: Animal) = Matter(animal.name, animal.weight)
implicit def vegetableToMatter(vegetable: Vegetable) = Matter(vegetable.name, vegetable.weight)
implicit def mineralToMatter(mineral: Mineral) = Matter(mineral.name, mineral.weight)
scala> Animal("Poodle", 1.0, 8.0).megaJouleMsg
res1: String = Poodle's mass-energy equivalence is 716612592013 megajoules.
编辑:看起来混淆是因为X <% Animal
。在animalToMatter
函数中,它需要一个隐式参数,可以使用X
并返回Animal
。现在,如果你在范围内看到没有这样的函数X => Animal
。但是因为你传递Animal("Poodle", 1.0, 8.0)
它不需要任何隐式函数,因为它已经获得了Animal
。
简而言之,在看到Animal("Poodle", 1.0, 8.0).megaJouleMsg
时重复编译过程:
Animal
并返回Matter
。 Animal
并返回Matter
。请注意,vegetableToMatter
和mineralToMatter
如果被接受将失败。即虽然他们有资格但他们不会成功,因为他们没有任何可用的隐含功能X => Animal
作为一个例子考虑一下:
scala> implicit def f[T <% Int](n:T) = Matter("",1)
warning: there were 1 feature warning(s); re-run with -feature for details
f: [T](n: T)(implicit evidence$1: T => Int)Matter
scala> 1.megaJouleMsg
res2: String = 's mass-energy equivalence is 89576574002 megajoules.
scala> "a".megaJouleMsg
<console>:12: error: No implicit view available from String => Int.
"a".megaJouleMsg
^
<console>:12: error: value megaJouleMsg is not a member of String
"a".megaJouleMsg
注意错误?它给出了:
String =&gt;中没有可用的隐式视图中间体
而不只是value megaJouleMsg is not a member of String
这意味着"a"
有资格使用隐式函数f
,但f
无法找到可将其转换为Int
的函数,因此它会给出错误{{ 1}}。如果它不符合函数No implicit view available...
的条件,那么它只会抛出错误f