在Scala中强制使用别名类型

时间:2015-06-23 07:03:10

标签: scala

在Scala中是否可以创建类似别名的东西,可用于强制执行某些条件?是的,我知道,这听起来有点奇怪,但让我说明一下我的意思。

我们想说我们只想拥有java.lang.Integer类型的正整数。这个类当然也允许负整数,因此在只允许正整数的情况下使用这种类型就不够了。我模糊的想法是拥有类似强制类型别名"。

// vague idea
object PositiveInteger {
  import java.lang.{Integer, Math}
  type PositiveInteger = Integer // something like this, but enforced
  def apply(value: Int) = new PositiveInteger(Math.abs(value))
}

然后我希望能够定义PositiveInteger类型的参数和值,并依赖于它们是正面的事实:

def calculate(value: PositiveInteger) = ...

我想避免将类包装在另一个(value)类中,因为我需要重复所有方法或者总是从外部访问包含包装对象的字段。

据我所知,在Scala中这是不可能的,但也许你知道实现这一目标的方法。你呢?

1 个答案:

答案 0 :(得分:4)

您可以在scalaz中使用此技术,在类型上添加标记 (http://eed3si9n.com/learning-scalaz/Tagged+type.html

// Entering paste mode (ctrl-D to finish)

  type Tagged[U] = {type Tag = U }
  type @@[T, U] = T with Tagged[U]

  object Tag {
    @inline def apply[T, U](t : T) : T @@ U = t.asInstanceOf[T @@ U]
  }

  sealed trait PositiveInt
  object PositiveInt {
    def apply(i : Int) : Int @@ PositiveInt = Tag(Math.abs(i))
    def unapply(p : Int @@ PositiveInt) : Option[Int] = Some(p)
  }

  // Exiting paste mode, now interpreting.

结果是:

defined type alias Tagged
defined type alias $at$at
defined object Tag
defined trait PositiveInt
defined object PositiveInt

scala> PositiveInt(4)
res0: @@[Int,PositiveInt] = 4

scala> PositiveInt(-4)
res1: @@[Int,PositiveInt] = 4

scala> res0 + res1
res2: Int = 8

但这种解决方案并不完美。

scala> PositiveInt(5) - PositiveInt(6)
res4: Int = -1


scala> PositiveInt(PositiveInt(5) - PositiveInt(6))
res5: @@[Int,PositiveInt] = 1

要获得完整的解决方案,您可能必须获得具有完整方法定义的真正类