class 需要是抽象的,因为 trait 中的方法未定义错误

class needs to be abstract since method in trait is not defined error

假设我们有一个基础 class(trait) 有两个方法(相同的名称,不同的参数,并且没有实现):

trait Base {
    def compute(arg1:type1, arg2:type2): returnType
    def compute(arg1:type1, arg2:type2, arg3:type3): returnType
}

我们有一些 class 继承自 Base。假设他们是 A、B、C。A 和 B 实现 "compute" 有两个参数,而 C 实现 "compute" 有三个参数。

class A  extends Base {
    def compute(arg1:type1, arg2:type2): returnType = {
        //detailed implementations
    }
}

class B  extends Base {
    def compute(arg1:type1, arg2:type2): returnType = {
        //detailed implementations
    }
}

class C  extends Base {
    def compute(arg1:type1, arg2:type2, arg3:type3): returnType = {
        //detailed implementations
    }
}

现在,我有一组这些对象 objs,我想自动选择要使用的 "compute" 版本:

val name = objs.map{ x =>
    val name = x.getClass.getSimpleName
    name match {
        case "C": x.compute(arg1, arg2, arg3)
        case _: x.compute(arg1, arg2)
    }
}

但是编译报错:

class A(B the same) needs to be abstract, since method compute in trait Base of type (three parameters) is not defined

我对这个错误感到困惑。那是因为 Base 中的所有方法都必须在其子 classes(A,B,C) 中实现吗?

有没有不编辑classA和classB的优雅修复(因为classC是最近设计的,compute必须多加一个参数, 所以我在上面又设计了一个功能)?

您需要在 AB 中定义 compute(arg1:type1, arg2:type2, arg3:type3) 并在 C 中定义 compute(arg1:type1, arg2:type2) 或者您可以提供默认值,否-op 在你的特征中实现

trait Base {
    def compute(arg1:type1, arg2:type2) {}
    def compute(arg1:type1, arg2:type2, arg3:type3) {}
}

我还建议在 Base

中明确定义 return 类型

编辑

使用案例 类:

的完整(简化)工作示例
trait Base {
  def compute(arg1: Int, arg2: Int): Int = 0
  def compute(arg1: Int, arg2: Int, arg3: Int): Int = 0
}

case class A() extends Base {
  override def compute(arg1: Int, arg2: Int): Int = arg1 + arg2
}

case class B() extends Base {
  override def compute(arg1: Int, arg2: Int): Int = arg1 - arg2
}

case class C() extends Base {
  override def compute(arg1: Int, arg2: Int, arg3: Int): Int = arg1 + arg2 - arg3
}

case class D(arg1: Int, arg2: Int, arg3: Int, objs: Seq[Base]) {
  val computed = objs map (_ match {
    case x: C    => x.compute(arg1, arg2, arg3)
    case x: Base => x.compute(arg1, arg2)
  })
}

你听说过接口隔离原则吗?

The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.1 ISP splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them. Such shrunken interfaces are also called role interfaces.

来源:Wikipedia

特征在某些方面与命名为 "interfaces" 的特征相似。

基本上,你必须拆分 Base 个特征。
Traits 代表 Scala 中的模块,保持它们较小是一个很好的做法,这样我们可以增加它们组合的能力并获得更大的抽象。

你最终会得到两个特征: (我只是把命名改得更清楚)

trait Computation {
  def compute(arg1:Int, arg2:Int): Unit
}

trait SpecificComputation {
  def compute(arg1:Int, arg2:Int, arg3:Int)
}

class A extends Computation {
  def compute(arg1:Int, arg2:Int) = {
    //detailed implementations
  }
}

class B  extends Computation {
  def compute(arg1:Int, arg2:Int) = {
    //detailed implementations
  }
}

class C extends SpecificComputation {
  def compute(arg1:Int, arg2:Int, arg3:Int) = {
    //detailed implementations
  }
}

如果你想要一个应该知道这两个 compute 方法变体的 class D,你写:

class D extends SpecificComputation with Computation {

      def compute(arg1:Int, arg2:Int) = {
        //detailed implementations
      }

      def compute(arg1:Int, arg2:Int, arg3:Int) = {
        //detailed implementations
      }
}

同意@Mik378。但如果您正在从 2 args 版本迁移到 3 args 版本,您可以:

trait Base {
  // Mark this as deprecated
  // No default implementation here because otherwise, A & B would need to 
  // be modified to add the 'override' keyword
  @deprecated
  def compute(arg1:type1, arg2:type2): returnType

  // Provide a default implementation for old implementations e.g. A / B
  def compute(arg1:type1, arg2:type2, arg3:type3): returnType =
    compute(arg1, arg2)
}

// Convenience base class for new implementations e.g. C
abstract class NewBase extends Base {
  override def compute(arg1: type1, arg2: type2): returnType =
    throw new UnsupportedOperationException
}

class A  extends Base {
  def compute(arg1:type1, arg2:type2): returnType = {
    //detailed implementations
  }
}

class B  extends Base {
  def compute(arg1:type1, arg2:type2): returnType = {
    //detailed implementations
  }
}

// All new implementations extend 'NewBase' instead of 'Base'
class C  extends NewBase {
  override def compute(arg1:type1, arg2:type2, arg3:type3): returnType = {
    //detailed implementations
  }
}

现在,您可以只对新旧 objs 使用 3-args 版本,

val name = objs.map(_.compute(arg1, arg2, arg3))