简体   繁体   English

Scala是否有类似于C#的显式接口实现?

[英]Does Scala have something similar to C#'s explicit interface implementation?

In C#, you can implement interfaces explicitely. 在C#中,您可以明确地实现接口。 The explicitely implemented methods can then only be called through a variable that has the interface as its static type. 然后,只能通过将接口作为其静态类型的变量来调用明确实现的方法。 This allows you to avoid name/return type conflicts and provide different implementations of the same method depending on the static type of this . 这可以让你避免名称/返回类型的冲突,并提供取决于静态类型的相同方法的不同实现this

For example: 例如:

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 */ }
}

How would you handle this case in Scala: 你会如何处理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... ? */
}

If you're just trying to make your class follow two separate incompatible interfaces, you'd have to write wrappers instead. 如果您只是想让您的类遵循两个独立的不兼容接口,那么您必须编写包装器。 For instance, 例如,

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

Now you can 现在你可以

impl.asFoo

at the use-site to switch over to the Foo wrapping. 在使用现场切换到Foo包装。

In some cases, though, it may be more natural use the type class pattern instead to provide pluggable functionality: 但是,在某些情况下,使用类型类模式代替提供可插入功能可能更自然:

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!

It's not exactly the same, but this also handles the issue of having different implementations without naming schemes tripping you up. 它并不完全相同 ,但这也解决了在没有命名方案绊倒你的情况下实现不同实现的问题。 (If you needed to doSomething with the impl object, you'd pass it as a parameter in the implicit object that handles that case.) (如果你需要doSomethingimpl对象,你通过它作为一个参数implicit object来处理这种情况。)

If you've already got traits, then of course this won't help you. 如果你已经有了特质,那么当然这对你没有帮助。 But when you're designing from scratch, rather than having a pile of traits with incompatible methods you might instead try type classes. 但是当你从头开始设计时,你可能会尝试输入类,而不是使用不兼容的方法。

Finally, if you cannot help having a bunch of untyped things jumbled together out of which you need to pick the Foo s, you have to invent more elaborate schemes like so: 最后,如果你无法帮助将一堆无用的东西混杂在一起,你需要选择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

You might prefer an intermediate map: 您可能更喜欢中间地图:

myList.map{ case cf: CanBeFoo => cf.asFoo; case x => x }.foreach{
  case f: Foo => println(f.doSomething)
  case _ => println("nuh-uh")
}

No, those are strictly incompatible base types. 不,这些是严格不兼容的基类型。 When a class extends a trait, it has that trait as a part of its type identity. 当一个类扩展一个特征时,它将该特征作为其类型标识的一部分。 It cannot have mutually incompatible type identities as would be the case for any class that extends Foo with Bar (as you wrote those traits). 它不能具有互不兼容的类型标识,就像任何extends Foo with Bar类一样(当你编写这些特征时)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM