2017-03-13 18 views
2

I持って、次のクラス: メソッドの戻り値の型の共変

trait Foo { 
    def update: Foo 
} 

class ConcreteFoo extends Foo { 
    override def update: Foo = new ConcreteFoo 
} 


class FooManager[T <: Foo](val foos: mutable.Map[String, T]) { 

    def update(id: String): Unit = { 
    foos.update(id, foos(id).update) 
    } 

} 

そしてもちろん

update関数がコンパイルされていません。

タイプmissmatchはfooが

T

必要見つかりました def update: Foo共変動型にするには?

trait Foo[T <: Foo[T]] { self: T => 
    def update: T 
} 

class ConcreteFoo extends Foo[ConcreteFoo] { 
    override def update = new ConcreteFoo 
} 


class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) { 

    def update(id: String): Unit = { 
    foos.update(id, foos(id).update) 
    } 

} 

代替、おそらく単純ルカが言ったように、溶液は、不変Mapを使用することで、:あなたはF-囲まれた多型のような何かをしたいよう

+0

変更可能なマップは、設計上不変です。変更可能なマップを使用しているときは、 'FooManager'を共変することはできません。 –

答えて

2

が見えます。

trait Foo { 
    def update: Foo 
} 

class ConcreteFoo extends Foo { 
    override def update: Foo = new ConcreteFoo 
} 


class FooManager(private var _foos: immutable.Map[String, Foo]) { 

    def foos = _foos 

    def update(id: String): Unit = { 
    _foos = _foos.updated(id, _foos(id).update) 
    } 
} 

あなたはまた、あなたの現在のソリューションを維持し、型パラメータを削除できます。しかし、その後はもう型パラメータを持っている必要はありません。しかし、のコンストラクタにmutable.Map[String,ConcreteFoo]を渡すことができないというわずかな不都合があります。

3

代わりに不変のマップを使用することをおすすめします。不変なコレクションだけが共変タイプパラメータを持つことができるためです。

class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) { 

    def update(id: String): FooManager[Foo] = { 
    new FooManager(foos.updated(id, foos(id).update)) 
    } 

} 
+0

私はそれを不変にすると、 'FooManager'の型パラメータを削除するだけでいいと思います。 –

+0

ええ、本当です。編集されました! –

+1

'update'は 'Foo'のメソッドなので、編集が間違っていました(最初の変種は正しいです)。メソッド名が混乱して申し訳ありません。はい、この解決策は正しいですが、私は 'def update(id:String):FooManager [Foo]'に更新プロトコルを変更できません。唯一の方法は、更新後にfoosを新しいコレクションに戻すことですが、 'var foos:immutable.Map [String、T]'は '共変型Tがcontravariant positionで発生する'コードをコンパイルしません。ジャスパーMさんの答えは、私にとってより適しています。 – zella

関連する問題