Scala มีอะไรคล้ายกับการใช้งานอินเทอร์เฟซที่ชัดเจนของ C # หรือไม่

ใน 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... ? */
}

person Tobias Brandt    schedule 16.07.2013    source แหล่งที่มา
comment
คุณสามารถใช้ยาชื่อสามัญ T? ไม่ใช่สิ่งที่คุณได้รับ 100% แต่ดูเหมือนว่าคุณสามารถใช้มันได้ คุณกำลังพยายามส่งคืนประเภทอื่นโดยใช้วิธีลายเซ็นเดียวกันหรือไม่? ตัวอย่างเช่น: คุณสามารถมี T DoSomething‹T›();   -  person Dr Schizo    schedule 16.07.2013


คำตอบ (2)


หากคุณเพียงพยายามทำให้ชั้นเรียนของคุณใช้อินเทอร์เฟซที่เข้ากันไม่ได้สองอินเทอร์เฟซแยกกัน คุณจะต้องเขียน wrappers แทน ตัวอย่างเช่น

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 คุณต้องคิดค้นรูปแบบที่ซับซ้อนมากขึ้น เช่น:

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

ไม่ สิ่งเหล่านี้เป็นประเภทพื้นฐานที่เข้ากันไม่ได้โดยเด็ดขาด เมื่อคลาสขยายลักษณะเฉพาะออกไป ก็จะมีลักษณะนั้นเป็นส่วนหนึ่งของอัตลักษณ์ประเภทของตน ไม่สามารถมีเอกลักษณ์เฉพาะตัวของประเภทที่เข้ากันไม่ได้เหมือนเช่นในกรณีของคลาสใดๆ ที่ extends Foo with Bar (ตามที่คุณเขียนคุณลักษณะเหล่านั้น)

person Randall Schulz    schedule 16.07.2013