避免Scala中的类型转换

时间:2014-05-23 18:20:22

标签: scala

我有这个奇怪的要求,其中数据来自服务的名称 - >值对以及所有名称 - >值类型只是字符串(实际上它们不是,而是数据的存储方式)

这是一个简化的插图。

case class EntityObject(type:String,value:String)

EntityObject("boolean","true")

现在当获取该EntityObject时,如果type为" boolean"然后我必须确保值不是除了布尔值之外的其他任何东西,所以首先输入类型并检查值并将值转换为该类型。例如,在这种情况下,检查值是布尔值,因此必须将字符串值转换为布尔值以进行验证。如果除了布尔值之外还有其他任何东西,那么它应该失败。

e.g。如果数据如下所示,则转换将失败,并且应该向调用者报告此错误。

EntityObject("boolean","1")

由于这种奇怪的要求,它强制在验证代码中进行类型转换,这种代码看起来并不优雅并且不符合类型安全编程。在scala中处理此问题的任何优雅方式(可能采用更安全的方式)?

2 个答案:

答案 0 :(得分:3)

在这里,我将引导Miles Sabin关于本地映射的推文中的想法(参见this gist on github。)如果您知道对象映射的类型,那么您可以使用涉及依赖类型的漂亮小技巧。坚持下去,因为这是一个疯狂的旅程:

trait AssocConv[K] { type V ; def convert: String => V }

def makeConv[V0](name: String, con: String => V0) = new AssocConv[name.type]{
  V = V0
  val convert = con
}

implicit val boolConv = makeConv("boolean", yourMappingFunc)

def convEntity(name: String, value: String)(implicit conv: AssocConv[name.type]): Try[conv.V] = Try{ conv.convert(value) }

我没有测试过这个,但它“应该”起作用。我还将其包含在Scala Try中,以便捕获转换函数抛出的异常(如果您正在执行转换器_.toInt之类的操作。)

答案 1 :(得分:0)

你真的在谈论转换,而不是铸造。如果值在运行时确实是布尔值的实例,那么将进行转换,而您拥有的是布尔值的String表示。

如果您已经在使用案例类,我认为模式匹配表达式在这里可以很好地工作。

例如,

def convert(entity : EntityObject) : Any = entity match {
  case EntityObject("boolean", "true") => true
  case EntityObject("boolean", "false") => false
  case EntityObject("string", s) => s
  // TODO: add Regex-based matchers for numeric types
}

任何与指定模式之一不匹配的东西都会导致MatchError,或者你可以在最后放置一个catchall表达式来抛出你自己的异常。

在这个特定的例子中,由于函数返回Any,调用咖啡需要进行实际的类型转换以获得特定类型,但至少到那时,所有验证/转换都已经执行过了。或者,您可以将使用值的代码直接放入上面的函数中,避免强制转换。我不知道你的具体需求是什么,所以我不能提供更详细的信息。