【发布时间】: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 很好,因为我觉得它可以更容易地推理代码。
【问题讨论】:
-
如何使用函数:
def calculate(f: Double => Double)(x: Double): Double = f(x)。您是否有特殊原因要使用扩展Double => Double的类和object? -
“我不想……”很少是技术决策的合理基础……
-
请注意,dotty(为 Scala 尝试新语言概念和编译器技术的平台)拥有它们:github.com/lampepfl/dotty/issues/640