use*_*663 2 scala field initialization
假设我有这两个类:
class Person (val name: String, val surname: String)
class Family (val nameFamily: String, val members: Set[Person])
Run Code Online (Sandbox Code Playgroud)
现在在main方法中实例化两个类,如下所示:
val F1 = new Family ("Red", Set(P1, P2))
val P1 = new Person ("John", "Smith")
val P2 = new Person ("Luis", "Smith")
Run Code Online (Sandbox Code Playgroud)
主要方法允许我在实例化之前输入家庭成员.我希望这是我的模特.但如果我在成员之前进入成员,那么当我去写作:
println(F1.members)
Run Code Online (Sandbox Code Playgroud)
我返回一个Set(null).
如果你先写下主要人物,就像这样:
val P1 = new Person ("John", "Smith")
val P2 = new Person ("Luis", "Smith")
val F1 = new Family ("Red", Set(P1, P2))
Run Code Online (Sandbox Code Playgroud)
我没有问题.
但是我想以任何顺序编写实例,最后运行一个家庭验证.
我可以解决这个问题.我的意思是,我可以使用稍后创建的实例初始化我的字段.
对不起英文翻译不好.
上传#1
我在Scala中实现了一个域,我使用DSL创建了域的实例.我的DSL允许我以混合顺序实例化类.例如,我创建一个Component,然后向该Component添加一些Type.然后我创建我添加到Component的Type.在主要方法中我可以做到.作为主要的最后一个陈述,我把验证.在开始验证时,键入组件没有找到任何内容,因为这些将在以后实例化.这个问题只能在主要用懒惰解决?或者是域级别的解决方案.
你可以使用lazy val:
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Person (val name: String, val surname: String)
case class Family (val nameFamily: String, val members: Set[Person])
lazy val f1 = new Family ("Red", Set(p1, p2))
lazy val p1 = new Person ("John", "Smith")
lazy val p2 = new Person ("Luis", "Smith")
// Exiting paste mode, now interpreting.
defined class Person
defined class Family
f1: Family = <lazy>
p1: Person = <lazy>
p2: Person = <lazy>
scala> f1
res0: Family = Family(Red,Set(Person(John,Smith), Person(Luis,Smith)))
Run Code Online (Sandbox Code Playgroud)
如果你想在创建对象之后的某个地方设置一些值,那么你应该使用scala 2.10中的Promise:
import concurrent.{Promise, Future}
case class Person (val name: String, val surname: String)
class Family (val nameFamily: String) {
private val membersPromice = Promise[Set[Person]]
def setMembers(m: Set[Person]) { membersPromice.success(m) }
val membersFuture = membersPromice.future
def members = membersFuture.value.map(_.get)
override def toString() = "Family(" + nameFamily + ", " + members.getOrElse("<future>") + ")"
}
Run Code Online (Sandbox Code Playgroud)
用法:
scala> val f = new Family("red")
f: Family = Family(red, <future>)
scala> val (p1, p2) = (Person("John", "Smith"), Person("Luis", "Smith"))
p1: Person = Person(John,Smith)
p2: Person = Person(Luis,Smith)
scala> f.setMembers(Set(p1, p2))
scala> f
res1: Family = Family(red, Set(Person(John,Smith), Person(Luis,Smith)))
scala> f.setMembers(Set(p1, p2))
java.lang.IllegalStateException: Promise already completed.
Run Code Online (Sandbox Code Playgroud)
您可以使用类型安全的构建器模式:
case class Person (val name: String, val surname: String)
case class Family (val nameFamily: String, val members: Set[Person])
sealed abstract class TBool
class TTrue extends TBool
class TFalse extends TBool
class FamilyBuilder[WithName <: TBool, WithMembers <: TBool](val nameFamily: Option[String], val members: Option[Set[Person]]) {
def withName(nameFamily: String)(implicit i: WithName =:= TFalse) = new FamilyBuilder[TTrue, WithMembers](Some(nameFamily), members)
def withMembers(members: Set[Person])(implicit i: WithMembers =:= TFalse) = new FamilyBuilder[WithName, TTrue](nameFamily, Some(members))
def create()(implicit i1: WithName =:= TTrue, i2: WithMembers =:= TTrue) = Family(nameFamily.get, members.get)
}
object FamilyBuilder {
def apply() = new FamilyBuilder[TFalse, TFalse](None, None)
}
Run Code Online (Sandbox Code Playgroud)
用法:
scala> FamilyBuilder() withName "Red" withMembers Set(p1, p2) create()
res1: Family = Family(Red,Set(Person(John,Smith), Person(Luis,Smith)))
scala> FamilyBuilder() withMembers Set(p1, p2) withName "Red" create()
res2: Family = Family(Red,Set(Person(John,Smith), Person(Luis,Smith)))
scala> FamilyBuilder() withName "Red" create()
<console>:1: error: Cannot prove that TFalse =:= TTrue.
FamilyBuilder() withName "Red" create()
^
Run Code Online (Sandbox Code Playgroud)