3

抽象型に関するOderskyetalによるScalaでのプログラミングの簡単な例がありますが、それは論理的な結論に従わないようです[これを私の正確なコードにするために編集されました]:

class Food
class Grass extends Food
class FishFood extends Food

abstract class Animal {
  type Feed <: Food
  def eat(food: Feed)
}

class Cow extends Animal {
  type Feed = Grass
  override def eat(food: Grass) = {}
}

class Test extends App {
  val cow: Animal = new Cow
  cow.eat(new FishFood)
  cow.eat(new Grass)
}

彼らはこれが私が(上記のように)するのを妨げるだろうと説明します:

val cow: Animal = new Cow
cow.eat(new FishFood)

ここまでは順調ですね。しかし、次の自然なステップも機能していないようです。

cow.eat(new Grass)

コンパイルエラーが発生します:

type mistmatch;
found : Grass
required: Test.this.cow.Feed
 cow.eat(new Grass)
         ^

しかし、cow.FeedはGrassなので、なぜこれが機能しないのですか?

4

2 に答える 2

8

ここでの問題は、valがではなくcowとして型指定されていることです。コンパイラが知っているのは、そのメソッドが特定のサブタイプのを期待していることだけですが、どちらかはわかりません。特に、その型がに等しいことを証明することはできません。。AnimalCoweatFoodGrass

eta-expansionを要求することで、これがメソッドのタイプ(から見た場合とから見た場合)の違いを確認できますAnimalCow

scala> val cow: Animal = new Cow
cow: Animal = Cow@13c02dc4

scala> cow.eat _
res12: cow.Feed => Unit = <function1>

scala> cow.asInstanceOf[Cow].eat _
res13: Grass => Unit = <function1>

Grass2番目の、より正確に型指定されたケースでは、コンパイラがメソッドを抽象型ではなく型の引数を取るものと見なしていることに気付くでしょうcow.Feed

于 2012-08-27T12:58:52.973 に答える
3

そして、それはそのように失敗するはずです-そして実際、私はそれがScalaのプログラミング(第2版、p.460)で説明されていると思います。

この行で:

val cow: Animal = new Cow

あなたはコンパイラーに、それは魚を含むどんな動物でもあり得ると仮定するように言いましたcow-そしてそれは確かに魚が草を食べるのに良くないでしょう!

コンパイラに適切な型を推測させると、次のようにコンパイルされます。

val cow = new Cow
cow.eat(new Grass)
于 2012-08-27T12:56:16.440 に答える