让我们考虑不断更新背景。在我的情况下,我有一个很大的功能,我传递了大量的参数,它们在后期阶段初始化并在之后使用。
例如,我不知道在实例初始化时我将从亚马逊获得什么IP,但我知道我将要使用的类型是IP
或String
,堆栈和实例ID相同。
后来我想使用某种协议连接到这个实例,所以我将使用这个参数。
我可以使用Option
的所有字段构建一个case类,但在我的情况下,这是一个过度杀伤,因为如果我没有成功提升一个实例,我将失败而不是使用Exception一个空的选项。这将导致大量无用的Option.get
。
现在的问题是:我可以使用哪种数据结构,而不是Option
,可以轻松复制(=>不可变),我可以在其中声明参数类型,但稍后会初始化它们?
答案 0 :(得分:2)
我看到2个选项
答案 1 :(得分:2)
我不太确定我是否理解你的观点,但我认为一种选择是模仿配置文件的读取方式,即使用地图字符串 - >数据类型。
您可以构建一个存储参数的常量字符串名称的“字典”对象,在这样的对象中,您还可以使用map - > String到所有参数的超类型。
object MyParameters {
var values: Map[String, Any] = Map ()
val ip = "IP"
val stack = "STACK"
}
def myInitFunction = {
import MyParameters._
if (values.contains(ip)) doSomethingWith(values(ip):IpType)
}
如果你想要存储每个参数的数据类型,你可以在对象中有一个双映射,一个从字符串到类型,另一个从字符串到值。您还可以通过在字符串的定义中对它们进行硬编码来预先定义值的类型 - >类型地图。由于这是一个对象,因此您无需复制任何内容
答案 2 :(得分:0)
可能你可以看看"类型安全的构建器"的不同实现。比如this one,但我所看到的都会产生很多样板代码。
其他不错的选择是自定义地图类型,其中包含具有类型信息的键,就像SBT一样
trait Key[T]
trait TypeSafeMap {
def apply(k: Key[T]): T
def update(k: Key[T], v: T)
}
答案 3 :(得分:0)
您可以在内部使用Option
字段作为外部接口,而不是使用Option.get
字段,并根据需要编写调用case class C(xOpt: Option[Int] = None, yOpt: Option[String] = None) {
def x = xOpt.get
def setX(value: Int) = copy(xOpt=Some(value))
def y = yOpt.get
def setY(value: String) = copy(yOpt=Some(value))
}
的getter和setter:
val c = C()
val c2 = c.setX(3)
val result = c2.x
所以在下面的例子中:
result
3
将为.get
,并且该类的用户无需致电Option
或了解基础val result2 = c2.y
。
y
会抛出异常,因为{{1}}尚未设置。
答案 4 :(得分:0)
我将此表示为两个案例类,一个用于收集可能无效的参数,另一个用于表示已验证的,具有所有paramteres-it-needs配置的案例类。
例如:
// this has all the info that happens in a 'valid' case
case class ValidConfig(ip: String, stack: String)
// this has placeholders for potentially invalid case
case class GatheringConfig(ip: Option[String], stack: Option[String])
然后,您需要一种可以将GatheringConfig
转换为ValidConfig
的方法,以便您可以直接引用所需的字段,并知道它们存在。此方法必须验证GatheringConfig
实例的字段,并且只有在存在所有必需字段时才构造ValidConfig
的实例。这可以通过几种方式实现,根据品味选择:
gatheringConfig.ip match { case None => throw new InvalidStateException() ... }
Either
或Try
表示无异常的错误,仅允许成功案例尝试构建ValidConfig
如果代码库中可以构建ValidConfig
实例的唯一位置在验证通过后确定所有必需字段(通过,例如编译器强制执行的可见性规则),则会获得积分。