2011-09-12 33 views
4

显然Range有一个方法来检查它是否包含Any类型的值。我知道它是从SeqLike,但会导致一些问题。Scala范围包含(elem:Any)方法

例如,我是从joda.DateTime匹配小时:

DateTime.now match { 
    case d if 0 to 12 contains d.hourOfDay() => ... 

这里d.hourOfDay()返回DateTime.Property,不中等,但仍代码编译由于contains(elem: Any)。有没有办法在编译时检查这种调用?

回答

6

可以pimpRange增加一个类型安全的contains方法:

class SafeRange(range: Range) { 
    def safeContains(i: Int) = range contains i 
} 

object SafeRange { 
    implicit def safer(range: Range) = new SafeRange(range) 
} 

导入隐含的任何范围的实例调用safeContains

scala> import SafeRange._ 
import SafeRange._ 

scala> (0 until 10) safeContains 3 
res2: Boolean = true 

scala> (0 until 10) safeContains 100 
res3: Boolean = false 

scala> (0 until 10) safeContains "foo" 
<console>:18: error: type mismatch; 
found : java.lang.String("foo") 
required: Int 
      (0 until 10) safeContains 
3

基于the scaladocs for Range它看起来好像没有更好的Range方法可以使用。您的选择似乎是

使用显式类型签名:

case d if 0 to 12 contains (d.hourOfDay(): Int) => ... 

使自己的方法:

def containsInt(r: Range, i: Int) = ... 

这似乎是从Java equals缓缴进行预仿制药,并且是这只是Scala造成的一个不便之处。

+1

是的......但也许应该有某种类型的编译器警告调用这种方法。在类型安全的语言中出现这样的运行时错误似乎是错误的。 – F0RR

+0

我很想拥有一个能够产生更多/更好的警告的插件。有这样的事吗? – ziggystar

+0

@ziggystar我不知道一个。我不知道编译器甚至可以告诉你这不是你想要的东西,而不是贬低该方法(这可能是正确的解决方案,但它有其他问题...) – Owen

7

您可以使用Scalaz的类型安全的equals(=== )与exists方法联合使用TraversableOnce

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> 1 to 5 exists { _ === 2 } 
res1: Boolean = true 

scala> 1 to 5 exists { _ === "Hullo" } 
<console>:14: error: type mismatch; 
found : java.lang.String("Hullo") 
required: Int 
     1 to 5 exists { _ === "Hullo" } 
          ^