Scala中的抽象静态方法

时间:2012-03-21 10:35:45

标签: scala abstract-class static-methods

我已经阅读了这篇相关文章,但没有多少具体答案(语言设计或多或少): Why can't static methods be abstract in Java

我是Scala的新手,这有可能吗(可能有特质或其他东西)?

我尝试让我的基类扩展一个特征,但是当我真的希望它们需要在伴随对象中实现时,需要子类来实现抽象静态方法作为成员方法。

4 个答案:

答案 0 :(得分:5)

Scala [*]中没有静态方法,所以你的问题没有实际意义。

但是,您可以通过使用特征扩展对象来获得所需内容:

scala> trait A { def foo(): Int }
defined trait A

scala> object C extends A { def foo(): Int = 5 }
defined module C

scala> C.foo
res0: Int = 5

这可能会做你想要的。实际上没有任何方法可以强制在类的伴随对象中实现某些东西。伴随对象可能不存在。

[*]从技术上讲,有,但这更像是一个实现细节,而不是整体哲学。见Method in companion object compiled into static methods in scala?

答案 1 :(得分:0)

为什么在Scala,Java,C ++或C#中无法实现抽象静态方法,有两种可能的解释。

首先是技术:抽象/虚拟方法需要引用一个对象(称为 this )来选择将要运行的覆盖。调用静态方法时,不提供此类对象。

第二是逻辑:抽象/虚拟静态方法没有任何意义。当您调用静态方法时,您始终知道包含该方法的类型。你写道:

MyClass.DoSomething(args)

如果你有扩展MyClass的MyDerivative,你可以定义另一个静态方法:

MyDerivative.DoSomethingDifferent(args)

静态虚拟方法没有意义,因为它们可以像普通的静态方法一样工作。

答案 2 :(得分:0)

我不确定你想用java中的抽象静态方法做什么,但我过去看到的唯一可能的用例(我希望我记得由谁......)方法直接在泛型类型参数上。

即。如果java允许这样的东西......

// this is not valid java...
// let's pretend we can define a static method in an interface
interface Foo {
    static String Foo();
}

// a class that implements our interface
class FooImpl implements Foo {
    public static String Foo() {return "foo";}  
}

...我们可以在泛型参数上使用它,直接在类型

上调用Foo()
static <T extends Foo> String Test() {
        return T.Foo(); // even if our hypothetical static interface
                        // was a valid thing, this would probably still fail
                        // due to type erasure      
}

这在C#中会更有意义,因为:

  1. 具体化的泛型意味着该类型不会被删除
  2. C#中的
  3. 运算符是静态方法,您可以define your own operators
  4. 基本上这意味着在“假装C#”中使用静态接口,您可以使用与上述“伪装java”代码相对应的内容来编写适用于定义特定运算符的任何类型的泛型方法(例如,具有“+”运算符)。

    现在,回到scala。 scala如何解决这种情况? 在某种程度上它没有。 Scala没有静态方法:一个对象是一个单例(即只有一个实例的类),但仍然是一个具有普通实例方法的类,即在对象上你仍然只调用唯一实例上的方法,而不是直接在类型上调用(甚至运算符都是scala中的方法。

    所以在scala中我们会写:

    trait Foo { def Foo:String }
    object FooImpl extends Foo { def Foo = "foo" }
    
    def Test(f: Foo) = f.Foo
    

    ...并使用

    调用我们的方法
    scala> Test(FooImpl)
    res0: String = foo
    // note that FooImpl is still an instance (the only one) of FooImpl and not 
    // the type itself
    

    您可以使用implicits做一些技巧,以避免将唯一的实例作为参数传递:

    implicit def aFoo = FooImpl
    def Test2(implicit f: Foo) = f.Foo
    

    现在可行:

    scala> Test2
    res1: String = foo
    

    使用带有implicits的更高级技巧,scala还定义了allows you to use operators on any numeric value的数字,即使它们没有实现开箱即用的公共接口。

答案 3 :(得分:0)

有一种方法,它实际上被所有scala集合使用:定义包含要实现的抽象静态方法定义的trait Companion,并在基本特征中添加一个抽象方法必须退回这个伴侣。

但是,为了使它工作,你必须使用一些棘手的类型参数:

// your trait - must give a ref to its companion
//   the type argument is made such that Self must extends MyTrait[Self]
//   and have as type argument of MyTrait the implementing subclass
trait MyTrait[Self <: MyTrait[Self]] { this: Self =>
  def companion: MyTraitCompanion[Self]
}

// the companion trait with required abstract static method
trait MyTraitCompanion[A <: MyTrait[A]] {
  def staticMethod: Int
}
// example of an implementing class of MyTrait, and MyTraitCompanion
case class SubClass(whatever: String) extends MyTrait[SubClass] {
  override def companion: MyTraitCompanion[SubClass] = SubClass
}

object SubClass extends MyTraitCompanion[SubClass] {
  override def staticMethod: Int = 42
}

// example of use
def print(t: MyTrait) = println("answer is " + t.companion.staticMethod)
print(SubClass("ultimate question"))

正如我上面所说,这实际上是由scala集合使用的:它们必须实现def companion: GenericCompanion[Self],这是GenericTraversableTemplate特征的抽象方法。不过,它比我的例子更复杂。