为了简化我的实际代码,我们假设有两个类,一个是另一个的子类:
class Chair {
val canFold = false;
// ...
}
class FoldableChair extends Chair {
val canFold = true;
// ...
}
Run Code Online (Sandbox Code Playgroud)
在我的实现中,我将有数百个其他子类的Chair或FoldableChair:
class Armchair extends ... {}
class DeckChair extends ... {}
//... etc
Run Code Online (Sandbox Code Playgroud)
对于这些子类中的每一个,假设每个子类都有一个冗长的实现,但我希望能够让它有时扩展Chair并有时扩展FoldableChair - 而不需要复制代码.我想在没有子类本身扩展的情况下这样做.这有可能吗?我需要使用特征来做到这一点吗?
我还希望能够创建子类的特定实例,有时会扩展Chair并有时扩展FoldableChair,但是在实例化时会做出这种选择.这也可能吗?谢谢!
编辑:澄清一下,我真正想要的是:
class Armchair extends Chair {}
class ArmchairFoldable extends FoldableChair {}
Run Code Online (Sandbox Code Playgroud)
但Armchair和ArmchairFoldable的实施完全相同.也就是说,我不想复制他们的实现.
假设我有一些traits,每个都为扩展的类添加一些行为Actor.
它们每个都需要一小部分方法Actor.他们都可以Actor像这样延伸吗?
trait A extends Actor {
def doAThing = { ... }
}
trait B extends Actor {
def doBThing = { ... }
}
trait C extends Actor {
def doCThing = { ... }
}
class D extends Actor with A with B with C
Run Code Online (Sandbox Code Playgroud)
或者每个特征是否应该从Actor抽象方法中定义它所需的方法,以便它们由最终的具体类提供,这是唯一一个将扩展的类Actor?
我是Scala的新手,来自Java,我只是在阅读有关特征的内容.经常提到的一件事是特征不会(不能?不会?)具有构造函数参数.我很想知道这是否有原因.
来自很久以前的数学/计算机科学背景,我想知道这是否是一个不可避免的后果,因为一些语言设计决定,或者是否有意识地决定避免一些继承/混合问题或其他?
希望有人知道,因为事实背后可能会有一些有趣的东西.
基本上,我正在尝试执行以下操作:
trait Foo[T] extends T {
def json: Writes[T]
def bar: String = {
Json.toJson[T](this)(json).toString
}
}
Run Code Online (Sandbox Code Playgroud)
我希望编译器强制使用trait Foo的任何类都是T类.不幸的是,'extends T'无效.现在,我能做的最好的事情如下:
trait Foo[T] extends T {
def json: Writes[T]
def bar: String = {
Json.toJson(this.asInstanceOf[T])(json).toString
}
}
Run Code Online (Sandbox Code Playgroud)
但显然,编译器没有强制执行任何操作.反正有没有实现我想要的?
我想知道以下行为背后的原因是什么?
@ trait Bar
defined trait Bar
@ trait Foo { self: Bar => }
defined trait Foo
@ def x: Foo = ???
defined function x
@ val y: Bar = x
cmd3.sc:1: type mismatch;
found : ammonite.$sess.cmd1.Foo
required: ammonite.$sess.cmd0.Bar
val y: Bar = x
^
Compilation Failed
Run Code Online (Sandbox Code Playgroud)
AFAIU,Foo要求其每个子类型都是 的子类型,Bar那么为什么实例Foo不是 的正确实例Bar?
@编辑
只是为了让问题更清楚:我想知道为什么它会这样工作。一些可能的答案是:
Foo而不是Bar运行时类型的实例)似乎至少 1) 有点正确(隐藏子类型作为实现细节)。
我想覆盖ScalaTest特性BeforeAndAfterEach,以便为我的所有测试实现一次.最后我得到它编译,但我不明白为什么.
trait MySetup extends BeforeAndAfterEach {
this : org.scalatest.BeforeAndAfterEach with org.scalatest.Suite =>
var service: String = _
abstract override def beforeEach(): Unit = {
service = "apa"
super.beforeEach()
}
abstract override def afterEach(): Unit = {
service = ""
}
}
Run Code Online (Sandbox Code Playgroud)
让它运作的是线:
this : org.scalatest.BeforeAndAfterEach with org.scalatest.Suite =>
Run Code Online (Sandbox Code Playgroud)
我在BeforeAndAfterEach实现的开头找到它并复制它.
它做了什么,为什么需要它?
更新:
这是一个更简单的版本.
trait MySetup extends FlatSpec with BeforeAndAfterEach {
var service: String = _
override def beforeEach {
service = "apa"
super.beforeEach
}
override def afterEach {
service = "" …Run Code Online (Sandbox Code Playgroud) 我有这个基于Akka Concurrency预打印的问题(最终版本还没有),使用它时没有解释.
在课程的第1版中,他们有:
class Altimeter extends Actor with ActorLogging with EventSource{
...
}
Run Code Online (Sandbox Code Playgroud)
声称Altimeter现在与EventSource紧密结合,因此测试Altimeter还需要测试EventSource.修复建议的更改如下:
--- a/src/main/scala/Altimeter.scala
+++ b/src/main/scala/Altimeter.scala
@@ -9,9 +9,10 @@ import scala.concurrent.ExecutionContext.Implicits.global
object Altimeter{
case class RateChange(amount: Float) //sent to Altimeter
case class AltitudeUpdate(altitude: Double)
+ def apply() = new Altimeter with ProductionEventSource
}
-class Altimeter extends Actor with ActorLogging with EventSource{
+class Altimeter extends Actor with ActorLogging{ this: EventSource =>
import Altimeter._
val ceiling = 43000 //feet
diff --git a/src/main/scala/EventSource.scala b/src/main/scala/EventSource.scala
index 1fd5578..ded4f38 100755
--- a/src/main/scala/EventSource.scala
+++ …Run Code Online (Sandbox Code Playgroud) scala> class A
defined class A
scala> trait T extends A { val t = 1 }
defined trait T
//why can I do this?
scala> class B extends T
defined class B
scala> new B
res0: B = B@2e9c76
scala> res0.t
res1: Int = 1
Run Code Online (Sandbox Code Playgroud)
我认为,当你写作时trait T extends A,它会让你只能将特性T放在一个类的子类上A.那我为什么要戴上呢B?这只适用于你混入的时候吗?为什么在宣布课程时这是不可能的?
scala ×8
traits ×6
self-type ×2
class-design ×1
generics ×1
inheritance ×1
oop ×1
scalatest ×1
subtyping ×1