【问题标题】:Parametrising Scala trait参数化 Scala 特征
【发布时间】:2016-10-10 16:03:04
【问题描述】:

免责声明:这个问题不是关于我是否应该这样做,或者它是否是一个好的设计或任何相关的推理。问题是我该怎么做。我稍后解释原因只是为了澄清。


我可以对 Scala 特征进行参数化吗?我知道他们不能有构造函数参数 - 有不同的方法吗?对于类似的东西(这只是一个例子,当然)

case class MyMachine(myDouble: Double) {
    def methodEveryMachineHas(): Double = 2 * myDouble
}

trait Drivable {
    this: MyMachine =>

    def drive(x: Double): Double = HowToDriveFunction(x) * myDouble

}

object HowToDriveFunction extends (Double => Double) {
    def apply(x:Double): Double = x + 6.0
}

val myMachine1 = new MyMachine(3.0)
myMachine1.methodEveryMachineHas // 6.0
myMachine1.drive(4.0) // error

val myMachine2 = new MyMachine(3.0) with Drivable
myClass1.methodEveryMachineHas // 6.0
myClass1.drive(4.0) // 30.0 = (4.0 + 6.0) * 3.0

如何将HowToDriveFunction 传递给drive

为什么我想要这个

将逻辑上不同的事物表示为程序化的不同事物,使代码有意义

函数应该固定在对象(= 实例化类)本身中。因此,我希望在创作过程中给予它。然而并不是所有的MyMachines 都应该有驱动能力。

想象MyMachine 是一台机器,Drivable 说它是可驱动的——如果某些东西不能通过逻辑驱动,我认为它在技术上也不应该是能够驱动的,因此是特性。但我仍然需要解释(通过HowToDriveFunction)这台特定机器(可能是汽车或飞机)的驱动是如何工作的。但是,我为什么要能够解释每台机器如何驱动呢?这是没有意义的。我只想向那些会开车的人解释一下。因此,我想将HowToDriveFunction 赋予特征(这表示机器可以驱动,因此首先应该能够驱动)。 如何驱动的工作原理不是能力(= 特质),而是对机制的描述,在我看来应该用函数来表示。如果它在逻辑上是不同的,那最好用不同的编程结构来表示。

当然,我的实际东西与机器等无关——这只是一个例子。

如果我的函数是通过另一个 trait 给出的,我可以写

trait HowToDriveFunction {
    this: Drivable =>
    ???
}

以确保只有 Drivable 的子类获得 HowToDriveFunction 的子类,但这对我来说似乎不是那么漂亮,原因已解释。

遵循“组合优于继承”

最后但并非最不重要的一点是,我认为拥有composition over inheritance 很好,因为我觉得它可以更容易地推理代码。

【问题讨论】:

标签: scala traits


【解决方案1】:

我不确定我是否完全理解这个问题,但似乎可以归结为

如何将HowToDriveFunction 传递给drive

并且能够在不被驱动的情况下定义MyMachine

为此,您只需在Drivable 中定义一个抽象成员。

case class MyMachine(myDouble: Double) {
  def methodEveryMachineHas: Double = 2 * myDouble
}

trait Drivable {
  this: MyMachine =>

  protected def driveFunction: Double => Double

  def drive(x: Double): Double = driveFunction(x) * myDouble
}

object HowToDriveFunction extends (Double => Double) {
  def apply(x: Double): Double = x + 6.0
}

val myMachine1 = new MyMachine(3.0)
myMachine1.methodEveryMachineHas // 6.0
myMachine1.drive(4.0) // error

val myMachine2 = new MyMachine(3.0) with Drivable { 
  val driveFunction = HowToDriveFunction
}
myMachine2.methodEveryMachineHas // 6.0
myMachine2.drive(4.0) // 30.0 = (4.0 + 6.0) * 3.0

【讨论】:

  • 这就是我要说的。谢谢。不过有一个问题:{...} 是否从 trait 中创建了一个类或对象,并使用 val driveFunction 对其进行初始化?
  • 只是MyMachine with Drivable的匿名子类(实现抽象方法)。你也可以写object MyDrivableMachine extends MyMachine(3) with Drivable { val driveFunction = ... }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多