【发布时间】:2014-12-25 15:10:01
【问题描述】:
我正在尝试定义一个期望值在外部范围内的可重用特征。我可以在外部范围内定义特征,它可以工作,但不能重用。当我将特征移动到单独的范围时,特征无法访问该值,并且我还没有找到一种方法来将其声明为存在于特征混合到的类型的外部范围中。
到目前为止,我得到的最接近的是:
import javafx.beans.property.ObjectProperty
import akka.actor.{Props, ActorSystem}
import javafx.event.EventHandler
import javafx.stage.{WindowEvent => JWindowEvent}
import scalafx.application.{Platform, JFXApp}
import scalafx.scene.Scene
import scalafx.scene.canvas.Canvas
import scalafx.scene.paint.Color
object MicroServicesApp extends JFXApp {
implicit val system = ActorSystem("system")
val canvas = new Canvas {
width = 1200
height = 900
}
stage = new MicroServicesPrimaryStage with AutomaticMicroServicesWindowCloser {
title.value = "Map Viewer"
scene = new Scene {
fill = Color.LightGreen
content = canvas
}
}
}
class MicroServicesPrimaryStage(implicit val actorSystem: ActorSystem) extends JFXApp.PrimaryStage with MicroServices {
}
/**
* A class enabled with a micro-services actor system.
*/
trait MicroServices {
def actorSystem: ActorSystem
}
/**
* An automatic window closer for a ScalaFX and Akka micro-services application.
*
* When this trait is mixed in to a class with the MicroServices trait and the onCloseRequest property,
* the onCloseRequest property will be initialized with a useful default event handler that shuts down
* the Akka actor system as well as the ScalaFX platform.
*/
trait AutomaticMicroServicesWindowCloser extends MicroServicesWindowCloser {
def onCloseRequest: ObjectProperty[EventHandler[JWindowEvent]]
def onCloseRequest_=(handler: EventHandler[JWindowEvent]): Unit
onCloseRequest = closeRequest()
}
/**
* A window closer for a ScalaFX and Akka micro-services application.
*/
trait MicroServicesWindowCloser extends MicroServices {
def closeRequest(): EventHandler[JWindowEvent] = new EventHandler[JWindowEvent] {
override def handle(e: JWindowEvent)
{
println("... closing application.")
actorSystem.shutdown()
Platform.exit()
}
}
}
它非常接近我所追求的,唯一的好处是客户端代码需要将外部范围内的值声明为隐式。理想情况下,我希望客户端代码在不更改任何其他内容的情况下混合特征。
在示例中,我可以在“MicroServicesPrimaryStage”中使用“system”,但不能在混合特征中使用。我认为这是因为“系统”在范围内,但不被视为被定义为“MicroServicesPrimaryStage”的成员。
我可以使用 val 或 def 为“system”创建别名并使其以这种方式工作,但这也意味着修改客户端代码的额外步骤。如果 trait 可能需要定义 'system' 并且 能够在混入 trait 的外部范围内找到它,那就太好了。
这可能吗?
编辑 1
这两个 println 语句说明了我的困惑的原因:
stage = new MicroServicesPrimaryStage with AutomaticMicroServicesWindowCloser {
println(s"val system is accessible from outer scope: $system ...") // compiles
println(s"... but is not mixed-in to MicroServicesPrimaryStage as ${this.system}.") // does not compile
...
我不认为蛋糕模式可以自己解决这个问题,因为问题在于类型系统如何与外部范围内的定义进行交互。
编辑 2
用于 Java 8 的 SBT 文件:
name := "workspace-sbt"
version := "1.0"
scalaVersion := "2.11.4"
resolvers += Opts.resolver.sonatypeSnapshots
libraryDependencies ++= Seq("org.scalatest" % "scalatest_2.11" % "2.2.1" % "test",
"org.scalafx" %% "scalafx" % "8.0.20-R7-SNAPSHOT",
"com.typesafe.akka" %% "akka-actor" % "2.3.7")
【问题讨论】:
-
不确定这是否有帮助,但是您可以声明对可以声明特征的位置的约束,例如:
trait Tax { this: Trade =>(来自:debasishg.blogspot.hu/2010/02/…) -
感谢您的建议。我尝试了自类型并选择直接扩展“微服务”而不是限制最终类型这样做。这可能是一个更好的起点,但我认为这两种方法都会导致编译器需要在最终类型(“MicroServicesPrimaryStage”)中明确定义“actorSystem”。我认为有趣的是,外部对象的成员不被视为在外部对象范围内混合在一起的类的成员。
-
我找到了解释差异的答案,也许自我类型更清楚地表达了意图:stackoverflow.com/questions/7250374/…
-
自包含代码很有帮助(或者是 build.sbt,因为我很懒),更新问题以反映 cmets 中的喋喋不休很有帮助。
标签: scala implicit traits self-type