Если вы просто пытаетесь заставить свой класс следовать двум отдельным несовместимым интерфейсам, вам придется вместо этого написать оболочки. Например,
implicit case class ImplAsFoo(impl: Impl) extends Foo {
def asFoo = this
def doSomething: Int = 5
}
Теперь вы можете
impl.asFoo
на сайте использования, чтобы переключиться на обертку Foo.
В некоторых случаях, однако, может быть более естественным использовать шаблон класса типа для обеспечения подключаемых функций:
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!
Это не в точности, но это также решает проблему наличия разных реализаций без сбоев в схемах именования. (Если вам нужно doSomething
с объектом impl
, вы должны передать его как параметр в implicit object
, который обрабатывает этот случай.)
Если у вас уже есть черты характера, то это, конечно, вам не поможет. Но когда вы разрабатываете с нуля, вместо того, чтобы иметь кучу черт с несовместимыми методами, вы можете вместо этого попробовать классы типов.
Наконец, если вы не можете избавиться от кучи нетипизированных вещей, перемешанных вместе, из которых вам нужно выбрать Foo
s, вам придется изобрести более сложные схемы вроде этой:
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
Вы можете предпочесть промежуточную карту:
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