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 }
但我想知道是否有更好的方法......
答案 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])