简体   繁体   English

Scala查看边界链接问题

[英]Scala View Bounds Chaining Issue

I know view bounds may be deprecated soon. 我知道视图边界很快就会被弃用。 Please ignore that. 请忽略它。

The following code compiles if only one of the last 3 implicit conversions are uncommented. 如果最后3个隐式转换中只有一个被取消注释,则以下代码进行编译。 Is this a compiler bug? 这是编译器错误吗?

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)
}

The error messages are: 错误消息是:

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)
                   ^

Well the compiler gives the error precisely. 那么编译器会精确地给出错误。 This is because there is more than one function which can Animal => Matter . 这是因为有多个函数可以使Animal => Matter ie your below 3 functions: 即你的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)

are equally eligible to be called when you do Animal("Poodle", 1.0, 8.0).megaJouleMsg . 当你做Animal("Poodle", 1.0, 8.0).megaJouleMsg时,同样有资格被Animal("Poodle", 1.0, 8.0).megaJouleMsg

When you call megaJouleMsg the compiler looks for any implicit function available that can take Animal and return an object containing method megaJouleMsg ( Matter in your case). 当你调用megaJouleMsg ,编译器会查找任何可用的隐式函数,它可以使用Animal并返回一个包含方法megaJouleMsg的对象(在你的情况下是Matter )。 Now all the 3 functions can take Animal (there is no constraint coded any where) and can return Matter . 现在所有3个函数都可以使用Animal (没有任何约束编码)并且可以返回Matter So the compiler gets confused on which function to calls 因此编译器对调用哪个函数感到困惑

Solution : From what it appears, the view bound is not required. 解决方案 :从显示的内容来看,不需要视图绑定。 This will do: 这样做:

  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.

Edit: Looks like the confusion is because of X <% Animal . 编辑:看起来混乱是因为X <% Animal In animalToMatter function, it expects an implicit argument which can take X and return Animal . animalToMatter函数中,它需要一个隐式参数,它可以接受X并返回Animal Now if you see in your scope there is no such function X => Animal . 现在,如果你在你的范围内看到没有这样的函数X => Animal But because you are passing Animal("Poodle", 1.0, 8.0) it doesn't need any implicit function because it has already obtained Animal . 但是因为你传递Animal("Poodle", 1.0, 8.0)它不需要任何隐含的功能,因为它已经获得了Animal

In short to repeat the compiler process on seeing Animal("Poodle", 1.0, 8.0).megaJouleMsg : 简而言之,重复编译过程看到Animal("Poodle", 1.0, 8.0).megaJouleMsg

  1. Sees all functions in the current scope which can take Animal and return Matter . 查看当前范围内的所有函数,这些函数可以使用Animal并返回Matter
  2. All the 3 functions can take Animal and return Matter . 所有3个函数都可以使用Animal并返回Matter Note that vegetableToMatter and mineralToMatter will fail if accepted. 请注意,如果接受, vegetableToMattermineralToMatter将失败。 ie though they are eligible but they will not succeed because they dont have any implicit function available that can X => Animal 即虽然它们符合条件,但它们不会成功,因为它们没有任何可用的隐式功能, X => Animal
  3. Throws Error 引发错误

As an example consider this: 举个例子考虑一下:

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      

Notice the error? 注意错误? It gives: 它给:

No implicit view available from String => Int. String => Int中没有可用的隐式视图。

and not just value megaJouleMsg is not a member of String 而不只是value megaJouleMsg is not a member of String

Which simply means "a" was eligible for the implicit function f but f could not find a function that could convert it to Int and hence it gives error No implicit view available... . 这简单地意味着"a"符合隐式函数f但是f找不到可以将其转换为Int的函数,因此它给出错误No implicit view available... If it was not eligible for function f , then it would just throw error megaJouleMsg is not a member... 如果它没有资格获得函数f ,那么它只会抛出错误megaJouleMsg is not a member...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM