Scala查看边界链接问题

时间:2014-03-04 05:26:15

标签: scala

我知道很快就会弃用视图边界。请忽略它。

如果最后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)
                   ^

1 个答案:

答案 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并返回包含方法megaJouleMsgMatter的对象)。现在所有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时重复编译过程:

  1. 查看当前作用域中的所有函数,可以Animal并返回Matter
  2. 所有3个功能都可以Animal并返回Matter。请注意,vegetableToMattermineralToMatter如果被接受将失败。即虽然他们有资格但他们不会成功,因为他们没有任何可用的隐含功能X => Animal
  3. 引发错误
  4. 作为一个例子考虑一下:

    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