2017-02-20 11 views
1

私は抽象型の話題に、スカラ座(マーティン・オーダーズキー、レックス・スプーンBill Vennersの共著)でのプログラミングの章20.7から基本的な例を持っています。 Iは、上述したようScalaの抽象型の洗練化に惑わされないようにする最良の方法はなぜですか?

class Food 
abstract class Animal { 
    type SuitableFood <: Food 
    def eat(food: SuitableFood) 
} 
class Grass extends Food 
class Cow extends Animal { 
    type SuitableFood = Grass 
    override def eat(food: Grass) {} 
} 
class Fish extends Food 
val bossy: Animal = new Cow // If the compiler were helpful, this would error. 
bossy.eat(new Grass) // error! 
// type mismatch; found: Grass, required: bossy.SuitableFood 

、動物として宣言され偉そう2行は、実際にはありません:以下のコードは、私が表向き前の例によって暗示ように見える最後の二つの行を追加したことを除いて、20.10リストからのものですこの例では、非常に合理的な概念的な飛躍と思われます。抽象クラスAnimal(ボッシュの宣言された型)のレベルでは、型メンバのPreferFoodはまだ抽象的です。つまり、たとえメソッド呼び出しでパス依存型が必要なように見えても、コンパイラを満足させるものはありません。

val bessy: Cow = new Cow 
bessy.eat(new Grass) // happy-happy 

私が偉そうするために「)(食べる」メソッドの呼び出しに置くことができるものはないことを考えると(次のように

私は、タイプの牛、メソッド呼び出しの作品のように、私のvalを宣言した場合コンパイラを満足させる動物)として宣言され、なぜコンパイラでも偉そうに/動物として宣言された牛としてインスタンス化することができるのですか?言い換えれば、オブジェクト宣言/インスタンス化を可能にするが、メソッド呼び出しを使用する可能性はありますか?抽象メンバ型精錬が意図的に通常のオブジェクト指向プログラミングでは禁止何かを許可するように見えることを考えるとScalaでは、この機能のための「ベストプラクティス」は、

ありますか?おそらく誰かがキラーを見つけたのでしょうか?

完璧な理にかなっているものとして、この動作を見るために私は非常に意欲。すなわち、サブタイプがスーパータイプよりも洗練されたタイプを有するような派生クラスでその型を精製、その後、抽象型を宣言し、この機能のための動機付けユースケースは何ですか?

+0

です。コンパイルエラーではありません。適切なサブタイプを取得して適切なメソッドを呼び出すことができるようにするには、依然としてあなたの上司のvalにパターンマッチさせることができます。 – Falmarri

+1

これは[ここ](http://stackoverflow.com/questions/20070998/abstract-type-in​​-scala)、[here](http:// stackoverflow。com/questions/20754143/no-dynamic-binding-when-abstract-type-scala)、[ここ](http://stackoverflow.com/questions/32161100/scala-types-class-a-is t-is-type-ta)、[ここ](http://stackoverflow.com/questions/37756383/path-dependent-types-example-doesnt-work)を参照してください。 )。 – jwvh

答えて

1

コンパイラを満たすためにbossy(動物として宣言された)の 'eat()'メソッド呼び出しに何も置くことができないとすれば、コンパイラはボッシーをAnimal /牛のようにインスタンス化?

  1. あり:bossy.eat((new Grass).asInstanceOf[bossy.SuitableFood])。もちろん、このようなコードを書く必要はありません。

  2. がなかったとしても、あなたがeatメソッドを呼び出すことなくbossyでできることがたくさんあります。

  3. などなど、そのハッシュコードを取得し、 List
0

をそれを置きますあなたはまだ他の便利なことをすることができます。あなたはそれがSuitableFoodであることを証明できる場合AnimalFoodを食べることができます。 Animalを投げることができたら、彼が投げたものはすべて彼が食べることができることを知っています。 GrassFishのいずれかがわからない場合でも、Foodだと分かります。したがって、すべての種類の可能性のある操作をFoodにすることができます。

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

abstract class Food { def name: String } 
class Grass extends Food { def name = "Grass" } 
abstract class Animal { 
    type SuitableFood <: Food 
    def eat(food: SuitableFood): Unit 
    def throwUp: Option[SuitableFood] 
} 

class Cow extends Animal { 
    type SuitableFood = Grass 
    private[this] var digesting: List[Grass] = Nil 
    def eat(food: Grass) { 
    digesting = food :: digesting 
    } 
    def throwUp = digesting match { 
    case Nil => None 
    case food :: rest => 
     digesting = rest 
     Some(food) 
    } 
} 

def dispose(food: Food) = println(s"Disposing of some ${food.name}.") 

// Exiting paste mode, now interpreting. 


scala> val animal: Animal = { val cow = new Cow; cow.eat(new Grass); cow } 
animal: Animal = [email protected] 

scala> animal.throwUp foreach animal.eat // can eat his own vomit :s 

scala> animal.throwUp foreach dispose // I can dispose of all food 
Disposing of some Grass. 
関連する問題