4

C# では、インターフェイスを明示的に実装できます。明示的に実装されたメソッドは、静的型としてインターフェイスを持つ変数を介してのみ呼び出すことができます。これにより、名前/戻り値の型の競合を回避し、 の静的型に応じて同じメソッドの異なる実装を提供できますthis

例えば:

interface IFoo
{
    int DoSomething();
}

interface IBar
{
    string DoSomething();
}

class Impl : IFoo, IBar
{
    int IFoo.DoSomething() { /* Implementation for IFoo */ }
    string IBar.DoSomething() { /* A different implementation for IBar */ }
    public void DoSomething() { /* Yet another implementation for Impl */ }
}

このケースを Scala でどのように処理しますか。

trait Foo {
    def doSomething(): Int
}

trait Bar {
    def doSomething(): String
}

class Impl extends Foo with Bar {
    /* only one "doSomething()" visible here (that of Bar?) */
    /* what now... ? */
}
4

2 に答える 2

3

クラスを 2 つの別個の互換性のないインターフェイスに従わせようとしているだけの場合は、代わりにラッパーを作成する必要があります。例えば、

implicit case class ImplAsFoo(impl: Impl) extends Foo {
  def asFoo = this
  def doSomething: Int = 5
}

今、あなたはすることができます

impl.asFoo

use-site で 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。)

すでに特性を持っている場合、もちろんこれは役に立ちません。しかし、ゼロから設計する場合は、互換性のないメソッドを持つトレイトを山積みにするのではなく、代わりに型クラスを試すことができます。

最後に、s を選択する必要がある型指定されていないものがごちゃまぜになっていることを避けられない場合はFoo、次のようなより複雑なスキームを発明する必要があります。

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")
}
于 2013-07-16T17:51:32.230 に答える
2

いいえ、それらは厳密に互換性のない基本型です。クラスがトレイトを拡張すると、そのトレイトが型のアイデンティティの一部になります。extends Foo with Bar(これらの特性を記述したように)クラスの場合のように、相互に互換性のない型 ID を持つことはできません。

于 2013-07-16T16:11:18.810 に答える