5

我想要 saInt_1to3UintScala 类型。最好有一个通用的工厂方法可以提供任何这样的方法。

它主要用于自我记录目的,但也会在到达时检查值(即通过“断言”)。

在我最初的(谷歌)搜索期间没有找到解决方案,我感到有些惊讶。我最接近的是Unsigned.scala,但这对我的需求来说太过分了。

这一定很简单

只是为了给出一个用法的想法,像这样的东西会很棒!:)

type Int_1to3= Int_limited( 1 to 3 )
type Uint= Int_limited( _ >= 0 )
4

5 回答 5

4

我看到了两个潜在的解决方案:

首先你可以看看Unboxed Type Tags。它们允许在编译时附加一个类型,而不必将整数装箱。编译器将强制在需要时使用它们,但在运行时检查值。

从引用的文章中,您可以编写如下内容:

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

trait Positive
trait One2Three

type PositiveInt = Int @@ Positive
type SmallInt = Int @@ One2Three

//Builds a small int
def small(i: Int): SmallInt = {
  require( i > 0 && i < 4, "should be between 1 and 3" )
  i.asInstanceOf[SmallInt]
}

//Builds a positive int
def positive( i: Int): PositiveInt = {
  require( i >= 0, "should be positive" )
  i.asInstanceOf[PositiveInt]
} 

//Example usage in methods
def mul( i: SmallInt, j: PositiveInt ): PositiveInt = positive(i*j)

然后在 REPL 中:

scala> mul( small(2), positive(4) )
res1: PositiveInt = 8

scala> mul( small(4), positive(2) ) //RUNTIME ERROR
java.lang.IllegalArgumentException: should be between 1 and 3


scala> mul( 2, positive(2) )       //COMPILE TIME ERROR
<console>:16: error: type mismatch;
 found   : Int(2)
 required: SmallInt
              mul( 2, positive(2) )
                   ^

第二种解决方案可能是为 Scala 2.10 提出的值类。您可以阅读SIP-15以了解如何使用它们。

于 2012-09-04T09:54:05.113 回答
2

您可以在此处使用的“模式”是使用私有构造函数声明密封类型作为底层值的包装器,该值仅限于可以验证和实例化的单个点。例如

sealed abstract class Int_1to3(val i:Int)
object Int_1to3 {
  def apply(i:Int):Option[Int_1to3] =
    if (1.to(3).contains(i)) Some(new Int_1to3(i){}) else None
}

这样,无论何时你最终得到一个xtype的实例Int_1to3,你都有一个编译时保证x.i将是1,23.

于 2012-09-04T04:59:02.593 回答
1

因为你有这样的“低标准”,这样做就足够了:

def safeInt(i: Int, f: Int => Boolean): Int =
  if (f(i)) i else throw new IllegalArgumentException("wrong int")

def int1to3(i: Int) =
  safeInt(i, 1 to 3 contains _)

def uInt(i: Int) =
  safeInt(i, _ >= 0)

当您不想强制编译器保持代码安全时,拥有这种 aa 类型没有多大意义。这是可能的,但正如你所说,不是为了你的需要。

于 2012-09-04T08:42:51.747 回答
0

昨天看了 Scalatest/Scalatric 3.0的视频,@Bill-Venners 在其中讨论了与我在 2012 年所要求的非常接近的类型PosIntPozInt

他还为我们提供了一个OddInt样本,让我们自己创建这样的价值类型。

于 2015-04-10T10:01:02.543 回答
0

不,语言中没有类似的东西。可用的解决方案——通过库——就是你所说的“overkillL”。

于 2012-09-04T03:16:07.147 回答