Scala - 类型安全"案例类"有空字段但不使用选项

时间:2014-11-04 14:17:22

标签: scala data-structures immutability

让我们考虑不断更新背景。在我的情况下,我有一个很大的功能,我传递了大量的参数,它们在后期阶段初始化并在之后使用。

例如,我不知道在实例初始化时我将从亚马逊获得什么IP,但我知道我将要使用的类型是IPString ,堆栈和实例ID相同。
后来我想使用某种协议连接到这个实例,所以我将使用这个参数。

我可以使用Option的所有字段构建一个case类,但在我的情况下,这是一个过度杀伤,因为如果我没有成功提升一个实例,我将失败而不是使用Exception一个空的选项。这将导致大量无用的Option.get

现在的问题是:我可以使用哪种数据结构,而不是Option,可以轻松复制(=>不可变),我可以在其中声明参数类型,但稍后会初始化它们?

5 个答案:

答案 0 :(得分:2)

我看到2个选项

  1. 使用不可变映射作为系统的配置对象,您可以在此处获得选项支持。
  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() ... }
  • 使用EitherTry表示无异常的错误,仅允许成功案例尝试构建ValidConfig
  • 如果你有野心勃勃,那就是验证的应用程序。

如果代码库中可以构建ValidConfig实例的唯一位置在验证通过后确定所有必需字段(通过,例如编译器强制执行的可见性规则),则会获得积分。