Scala中的抽象静态方法

Scala中的抽象静态方法,scala,abstract-class,static-methods,Scala,Abstract Class,Static Methods,我读过这篇相关的文章,但没有太多具体的答案(或多或少是糟糕的语言设计): 我对Scala有点陌生,这在它里面是可能的吗(也许有一些特征或其他) 我试着让我的基类扩展一个trait,但是当我真的希望在伴生对象中实现抽象静态方法时,子类需要作为成员方法来实现抽象静态方法。Scala[*]中没有静态方法,所以你的问题没有意义 但是,您可以通过扩展具有以下特征的对象来获得所需: scala> trait A { def foo(): Int } defined trait A scala>

我读过这篇相关的文章,但没有太多具体的答案(或多或少是糟糕的语言设计):

我对Scala有点陌生,这在它里面是可能的吗(也许有一些特征或其他)


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

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
这可能正是你想要的。实际上没有任何方法可以强制在类的伴生对象中实现某些东西。伴生对象可能不存在


[*]从技术上讲,有,但这更多的是一个实现细节,而不是一个总体理念。在斯卡拉、java、C++或C语言中,抽象静态方法不可能存在两种可能的解释。 首先是技术性的:抽象/虚拟方法需要对对象(称为this)的引用来选择将运行的重写。调用静态方法时,不提供此类对象

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

MyClass.DoSomething(args)
如果您有扩展MyClass的MyDerivation,您可以定义另一个静态方法:

MyDerivative.DoSomethingDifferent(args)

静态虚拟方法没有任何意义,因为它们将与普通静态方法一样工作。

我不确定您想用java中的抽象静态方法做什么,但我在过去看到的唯一一个潜在用例(我希望我记得是谁…)直接对泛型类型参数调用方法

i、 如果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      
}
…并使用

scala> Test(FooImpl)
res0: String = foo
// note that FooImpl is still an instance (the only one) of FooImpl and not 
// the type itself
可以使用隐式执行一些技巧,以避免将唯一实例作为参数传递:

implicit def aFoo = FooImpl
def Test2(implicit f: Foo) = f.Foo
现在,这项工作:

scala> Test2
res1: String = foo

通过更高级的隐式技巧,scala还定义了Numeric,即使它们没有实现现成的通用接口。

有一种方法,实际上被所有scala集合使用:定义一个trait
Companion
,其中包含要实现的抽象静态方法的定义,并在基本trait中添加一个抽象方法,该方法必须返回此同伴

但是,要使其工作,必须使用一些棘手的类型参数:

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

正如我上面所说的,scala集合实际上使用了这种方法:它们必须实现
def companion:GenericCompanion[Self]
,这是
GenericTraversableTemplate
特性的一种抽象方法。但是,它比我的示例更复杂。

实际上,ComAnyon对象的方法可以被视为类的静态方法。@Nicolas是的,类中有一个静态转发器,但正如我所说的,这更多是一个实现细节,有助于与Java进行互操作。Scala语言本身没有静态方法的概念。它更像是一个单体,怎么可能伴星不存在呢?这不应该在编译时解决吗?@JiaweiLi Scala不会创建伴生对象,除非您指定伴生对象或使用case类。如果指定类Foo{},则不会自动创建对象Foo。所以你不能假设对象Foo会存在。出于好奇,这不是语言设计中的一个缺陷吗?(无法强制存在伴生对象和某些特定方法)这是一个有意识的决定吗?通过“抽象静态方法”,人们通常指的是必须由任何具体子类静态实现的方法。虽然我同意它的形状不好,但它们的存在是有道理的。例如,请参见scala collections如何使用“标准方法”强制创建伴生对象。您能告诉我们有关您的特定场景的更多信息吗?为什么需要将方法放在伴生对象中?在scala中可能有一种不同的方法来实现它。下面是一个例子:我的基本抽象类有一个抽象自动更正方法,它不需要绑定到特定的实例。我正在考虑在使用这种自动更正方法的基本抽象类中实现方法。如果功能不需要在子类中重写,那么我的子类将需要实现它们自己的自动更正方法-因此抽象静态方法。如果您所做的只是调用一个未绑定到特定实例的方法,则将该方法放入伴随对象中,从你的类和所有子类中调用它。这在Scala中是正常的做法。自动更正方法在我的基类中是抽象的。问题是没有办法强制我的子类来实现自动更正方法。@JiaweiLi事实是scala对象中的方法(与java中的静态方法不同)仍然是实例方法,因此在客户端,调用它们的方式没有语义上的差异。当您在scala中编写AnObject.AMethod时,您并不是在类型上调用AMethod,只是AnObject为您提供了singleton AnObject类的唯一实例。请看我在哪里解释了我的意思
// 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"))