저는 스칼라로 작성된 작은 GUI 응용 프로그램을 만들고 있습니다. 사용자가 GUI에서 설정하는 몇 가지 설정이 있으며이를 프로그램 실행간에 유지하려고합니다. 기본적으로 나는 scala.collections.mutable.Map을 원한다. 수정 될 때 파일에 자동으로 지속된다.Scala 응용 프로그램의 기본 구성은 어떻게 제공합니까?
일반적인 문제 일 것 같지만 경량 솔루션을 찾지 못했습니다. 이 문제는 일반적으로 어떻게 해결됩니까?
저는 스칼라로 작성된 작은 GUI 응용 프로그램을 만들고 있습니다. 사용자가 GUI에서 설정하는 몇 가지 설정이 있으며이를 프로그램 실행간에 유지하려고합니다. 기본적으로 나는 scala.collections.mutable.Map을 원한다. 수정 될 때 파일에 자동으로 지속된다.Scala 응용 프로그램의 기본 구성은 어떻게 제공합니까?
일반적인 문제 일 것 같지만 경량 솔루션을 찾지 못했습니다. 이 문제는 일반적으로 어떻게 해결됩니까?
나는 이것을 많이하고 .properties 파일을 사용한다. (Java-land에서는 관용적이다.) 그래도 내 설정을 꽤 간단하게 유지합니다. 중첩 된 설정 구성을 가지고 있다면 YAML (사람이 주 저자 인 경우)이나 JSON 또는 XML (기계가 작성자 인 경우)과 같은 다른 형식이 필요할 수 있습니다.
import java.io._
import java.util._
import scala.collection.JavaConverters._
val f = new File("test.properties")
// test.properties:
// foo=bar
// baz=123
val props = new Properties
// Note: in real code make sure all these streams are
// closed carefully in try/finally
val fis = new InputStreamReader(new FileInputStream(f), "UTF-8")
props.load(fis)
fis.close()
println(props) // {baz=123, foo=bar}
val map = props.asScala // Get to Scala Map via JavaConverters
map("foo") = "42"
map("quux") = "newvalue"
println(map) // Map(baz -> 123, quux -> newvalue, foo -> 42)
println(props) // {baz=123, quux=newvalue, foo=42}
val fos = new OutputStreamWriter(new FileOutputStream(f), "UTF-8")
props.store(fos, "")
fos.close()
asScala는 중첩 형식에 사용할 수 있습니까?JSON 객체와 같은 것을로드한다고 가정 해 봅시다. 일부 값이 다른지도 또는 목록이고 다른지도, 목록, 숫자, 문자열 등을 포함하는지도를 다시 가져오고 싶을 수도 있습니다. – user48956
지도를 속성으로 변환하거나 그 반대의 경우를 권장합니다. "* .properties"파일은 Java 환경에서 구성을 저장하기위한 표준입니다. 스칼라에 사용하지 않는 이유는 무엇입니까?
일반적인 방법은 *입니다. 속성, * .xml, scala는 기본적으로 xml을 지원하므로 java에서 xml config를 사용하면 더 쉽습니다.
가 여기에 설정을 읽기위한 XML 및 케이스 클래스를 사용하는 예이다 :
는 여기서 다시 .properties 파일로 저장 한 후, 스칼라지도로 조작,로드 소품에 대한 몇 가지 예제 코드입니다. 실제 수업은지도보다 좋을 수 있습니다. (당신은 또한 sbt와 적어도 하나의 프로젝트가 스칼라 소스로 설정을 가져 와서 컴파일 할 수 있습니다; 저장은 자동으로 수행하지 않습니다. 또는 repl 스크립트로 수행합니다. 나는 봤지만 굳이 찾아 내지 못했을 것입니다.
이case class PluginDescription(name: String, classname: String) {
def toXML: Node = {
<plugin>
<name>{name}</name>
<classname>{classname}</classname>
</plugin>
}
}
object PluginDescription {
def fromXML(xml: Node): PluginDescription = {
// extract one field
def getField(field: String): Option[String] = {
val text = (xml \\ field).text.trim
if (text == "") None else Some(text)
}
def extracted = {
val name = "name"
val claas = "classname"
val vs = Map(name -> getField(name), claas -> getField(claas))
if (vs.values exists (_.isEmpty)) fail()
else PluginDescription(name = vs(name).get, classname = vs(claas).get)
}
def fail() = throw new RuntimeException("Bad plugin descriptor.")
// check the top-level tag
xml match {
case <plugin>{_*}</plugin> => extracted
case _ => fail()
}
}
}
이 코드는 반사적이 경우 클래스의 적용 호출)
이 버전의 경우 클래스를 사용합니다. 유스 케이스는 config에서 누락 된 필드가 기본 args에 의해 제공 될 수 있다는 것이다. 여기서 유형 변환이 없습니다. 예 : case class Config(foo: String = "bar")
.
// isn't it easier to write a quick loop to reflect the field names?
import scala.reflect.runtime.{currentMirror => cm, universe => ru}
import ru._
def fromXML(xml: Node): Option[PluginDescription] = {
def extract[A]()(implicit tt: TypeTag[A]): Option[A] = {
// extract one field
def getField(field: String): Option[String] = {
val text = (xml \\ field).text.trim
if (text == "") None else Some(text)
}
val apply = ru.newTermName("apply")
val module = ru.typeOf[A].typeSymbol.companionSymbol.asModule
val ts = module.moduleClass.typeSignature
val m = (ts member apply).asMethod
val im = cm reflect (cm reflectModule module).instance
val mm = im reflectMethod m
def getDefault(i: Int): Option[Any] = {
val n = ru.newTermName("apply$default$" + (i+1))
val m = ts member n
if (m == NoSymbol) None
else Some((im reflectMethod m.asMethod)())
}
def extractArgs(pss: List[List[Symbol]]): List[Option[Any]] =
pss.flatten.zipWithIndex map (p => getField(p._1.name.encoded) orElse getDefault(p._2))
val args = extractArgs(m.paramss)
if (args exists (!_.isDefined)) None
else Some(mm(args.flatten: _*).asInstanceOf[A])
}
// check the top-level tag
xml match {
case <plugin>{_*}</plugin> => extract[PluginDescription]()
case _ => None
}
}
XML은 loadFile
및 save
가이 Properties
에 대한 한 줄 없을 것 같다 너무 나쁘다. 모든 파일에지도/객체 직렬화로 귀결로서
$ scala
Welcome to Scala version 2.10.0-RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_06).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import reflect.io._
import reflect.io._
scala> import java.util._
import java.util._
scala> import java.io.{StringReader, File=>JFile}
import java.io.{StringReader, File=>JFile}
scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._
scala> val p = new Properties
p: java.util.Properties = {}
scala> p load new StringReader(
| (new File(new JFile("t.properties"))).slurp)
scala> p.asScala
res2: scala.collection.mutable.Map[String,String] = Map(foo -> bar)
, 당신의 선택은 다음과 같습니다
나는 json4s https://github.com/json4s/json4s를 사용하여 JSON에 직렬화를 종료했다. 모든 제안을 주셔서 감사합니다. – Dave