gpt4 book ai didi

scala - 如何将外部范围的值隐式注入(inject) Scala 特征

转载 作者:行者123 更新时间:2023-12-04 20:59:27 25 4
gpt4 key购买 nike

我正在尝试定义一个可重用的特征,它期望一个值在外部范围内。我可以在外部范围内定义特征,它会起作用,但不能重复使用。当我将 trait 移动到一个单独的范围时,该 trait 无法访问该值,而且我还没有找到一种方法来将它声明为存在于该 trait 混合到的类型的外部范围内。

到目前为止我得到的最接近的是:

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”中使用“系统”,但不能在混合特性中使用。我认为这是因为“系统”在范围内,但未被视为定义为“MicroServicesPrimaryStage”的成员。

我可以使用 val 或 def 为“系统”创建别名并使其以这种方式工作,但这也意味着修改客户端代码的额外步骤。如果特征需要“系统”的定义并且能够在混合特征的外部范围内找到它,那就太好了。

这可能吗?

编辑 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")

最佳答案

你错了:

“在示例中,我可以在‘MicroServicesPrimaryStage’中使用‘system’,但不能在混合特征中使用。我认为这是因为‘system’在范围内,但未被视为定义为“MicroServicesPrimaryStage”的成员。”

这不是真的。您当然可以使用父类(super class)成员作为混合特征的抽象成员的定义。考虑一下:

trait Foo { 
def foo: String
def printFoo = println(foo)
}

class FooBar(val foo)

object FooBar {
def main(argv: Array[String]) = new FooBar("foo") with Foo printFoo
}

这会编译并在运行时打印“foo”。这不是你想要做的吗?

关于scala - 如何将外部范围的值隐式注入(inject) Scala 特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27648382/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com