Jika Anda hanya mencoba membuat kelas Anda mengikuti dua antarmuka terpisah yang tidak kompatibel, Anda harus menulis wrapper. Contohnya,
implicit case class ImplAsFoo(impl: Impl) extends Foo {
def asFoo = this
def doSomething: Int = 5
}
Sekarang kamu bisa
impl.asFoo
di situs penggunaan untuk beralih ke pembungkus Foo.
Namun, dalam beberapa kasus, mungkin lebih alami menggunakan pola kelas tipe untuk menyediakan fungsionalitas yang dapat dicolokkan:
trait IFoo[A] { def doSomething: Int }
trait IBar[A] { def doSomething: String }
// These need to be companions so :paste if you're using REPL
class Impl { def doSomething { println("Hey!") } }
object Impl {
implicit object FooImpl extends IFoo[Impl] { def doSomething = 5 }
implicit object BarImpl extends IBar[Impl] { def doSomething = "salmon" }
}
def needsFoo[A <: Impl: IFoo](a: A) = implicitly[IFoo[Impl]].doSomething
scala> needsFoo(new Impl)
res1: Int = 5
scala> (new Impl).doSomething
Hey!
Ini tidak persis sama, tetapi ini juga menangani masalah penerapan yang berbeda tanpa memberi nama skema yang membuat Anda tersandung. (Jika Anda perlu doSomething
dengan objek impl
, Anda akan meneruskannya sebagai parameter di implicit object
yang menangani kasus tersebut.)
Jika Anda sudah memiliki ciri-cirinya, tentu saja hal ini tidak akan membantu Anda. Namun ketika Anda mendesain dari awal, daripada memiliki tumpukan sifat dengan metode yang tidak kompatibel, Anda mungkin mencoba kelas tipe.
Terakhir, jika Anda tidak dapat menahan diri untuk mencampurkan banyak hal yang belum diketik sehingga Anda harus memilih Foo
, Anda harus membuat skema yang lebih rumit seperti ini:
trait CanBeFoo { def asFoo: Foo }
trait Foo { def doSomething: Int }
// :paste these two together
class Impl extends CanBeFoo {
def doSomething { println("Ho!") }
def asFoo = ImplAsFoo(this)
}
case class ImplAsFoo(impl: Impl) extends Foo {
def doSomething = 6
}
val myList = List("salmon", new Impl, new Foo { def doSomething = 4 })
def doIt(f: Foo) { println(f.doSomething) }
myList.foreach {
case f: Foo => doIt(f)
case cf: CanBeFoo => doIt(cf.asFoo)
case _ => println("nuh-uh")
}
// Produces
// nuh-uh
// 6
// 4
Anda mungkin lebih memilih peta perantara:
myList.map{ case cf: CanBeFoo => cf.asFoo; case x => x }.foreach{
case f: Foo => println(f.doSomething)
case _ => println("nuh-uh")
}
person
Rex Kerr
schedule
16.07.2013