如何安全地传递字符串值类型?

时间:2014-02-21 15:53:09

标签: scala type-safety

E.g:

def updateAsinRecords(asins:Seq[String], recordType:String)

上面的方法需要Seq个ASIN和一个记录类型。两者都有String的类型。还有其他值在应用程序中传递类型String。不用说,这是Scala,我想使用类型系统对我有利。如何以类型安全的方式传递字符串值(如下所示)?

def updateAsinRecords(asins:Seq[ASIN], recordType:RecordType)
                                ^                 ^

我可以想象,有这样的事情:

trait ASIN { val value:String }

但我想知道是否有更好的方法......

4 个答案:

答案 0 :(得分:3)

您可以添加包含案例类的精简包装器:

case class ASIN(asin: String)
case class RecordType(recordType: String)

def updateAsinRecords(asins: Seq[ASIN], recordType: RecordType) = ???

updateAsinRecords(Vector(ASIN("a"), ASIN("b")), RecordType("c"))

这不仅可以使您的代码更安全,而且还可以使您的代码更容易阅读!这种方法的另一大优势是稍后重构将更容易。例如,如果您稍后决定ASIN应该有两个字段而不是一个字段,那么您只需更新ASIN类定义而不是每个使用它的位置。同样,您可以在决定需要时为这些类型添加方法。

答案 1 :(得分:3)

有一些新的Scala功能称为Value Classes and Universal Traits。它们不会产生运行时开销,但您可以使用它们以类型安全的方式工作:

class AnsiString(val inner: String) extends AnyVal
class Record(val inner: String) extends AnyVal

def updateAnsiRecords(ansi: Seq[AnsiString], record: Record)

它们是专门为此目的而创建的。

答案 2 :(得分:3)

除了有关使用值类/ extends AnyVal的建议之外,您应该控制构造以仅允许有效实例,因为可能不是任何旧字符串都是有效的ASIN。 (并且......这是亚马逊的东西吗?它以某种方式敲响了铃声。)

执行此操作的最佳方法是使构造函数为私有,并将验证工厂方法放在随播对象中。这样做的原因是在构造函数中抛出异常(当尝试使用无效参数进行实例化时)会导致令人费解的失败模式(我经常看到它在尝试加载不同的类时表现为NoClassDefFoundError错误)。

所以,除了:

case class ASIN private (asin: String) extends AnyVal { /* other stuff */ }

你应该包括这样的东西:

object A {
  import scala.util.{Try, Success, Failure}

  def fromString(str: String): Try[ASIN] =
    if (validASIN(str))
      Success(new ASIN(str))
    else
      Failure(new InvalidArgumentException(s"Invalid ASIN string: $str")
}

答案 3 :(得分:0)

类型别名怎么样?

type ASIN = String

def update(asins:Seq [ASIN])