1

我想在 Scala 中编写以下内容:

def method(a: Float, b: Float, c: Float) = {
  if( a < b <= c) {
    ...
  }
}

目前,这是无效的。实际上,a < b返回一个布尔值,出于比较的目的,它被一个 包裹起来booleanWrapper。然后编译器抱怨 c 是 typeFloat而不是Boolean,所以它根本不b比较c

是否可以使用隐式类、方法和值类来实现这一点?

目前,我只能做到以下几点:

class Less(val previous: Boolean, last: Float) {
  def <=(other: Float): Less = new Less(previous && last <= other, other)
  def <(other: Float): Less = new Less(previous && last < other, other)
}
implicit def f(v: Float): Less = {
  new Less(true, v)
}
implicit def lessToBoolean(f: Less): Boolean = {
  f.previous
}

def method(a: Float, b: Float, c: Float) = {
  if( f(a) < b <= c) {
    ...
  }
}

有什么方法可以使用标准技巧删除这个 f 吗?

4

2 回答 2

3

是的,您可以使用隐式和自定义运算符来模拟这一点。这是一个简短的例子:

implicit class FloatWrapper(n:Float) {
  def :<(that:Float) = ResultAndLastItem(n<that, that)
  def :>(that:Float) = ResultAndLastItem(n>that, that)
  def :=(that:Float) = ResultAndLastItem(n==that, that)
  // insert more comparison operations here
}

case class ResultAndLastItem(result:Boolean, lastItem:Float) extends FloatWrapper(lastItem) {
  // insert boolean operations here
  // boolean operations should return another instance of ResultAndLastItem (?)
}

implicit def toBoolean(r:ResultAndLastItem):Boolean = r.result

这是 REPL 中的示例用法:

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

implicit class FloatWrapper(n:Float) {
  def :<(that:Float) = ResultAndLastItem(n<that, that)
  def :>(that:Float) = ResultAndLastItem(n>that, that)
  def :=(that:Float) = ResultAndLastItem(n==that, that)
  // insert more comparison operations here
}

case class ResultAndLastItem(result:Boolean, lastItem:Float) extends FloatWrapper(lastItem) {
  // insert boolean operations here
  // boolean operations should return another instance of ResultAndLastItem (?)
}

implicit def toBoolean(r:ResultAndLastItem):Boolean = r.result

// Exiting paste mode, now interpreting.

warning: there were 1 feature warnings; re-run with -feature for details
defined class FloatWrapper
defined class ResultAndLastItem
toBoolean: (r: ResultAndLastItem)Boolean

scala> if(2 :< 3 :< 4) "yay" else "nope"
res0: String = yay

scala> if(2 :< 3 :< 3) "nope" else "yay"
res1: String = yay

评论:

  • 您可以轻松添加更多比较运算符,例如:<=.

  • 需要使用自定义运算符,因为这会强制编译器使用implicit class上述运算符,而不是 s 的内置默认运算符Float

  • 很难让我的示例更通用,以便允许所有可比较的类型,例如DoubleInt或自定义类型。这很难的原因是因为implicit class FloatWrapper不能需要进一步的implicit参数 - 不能嵌套隐式。(或者更准确地说,它们可以在语法上,但是编译器不会选择它们进行隐式解析。)

  • 作为一种优化,您可能需要考虑添加布尔快捷方式,即当已知表达式为 时false,无需评估剩余的比较。

    • 当您还添加布尔运算符(例如||or )时,这变得很棘手&&
于 2013-06-20T10:10:40.107 回答
1

如果您使用具有方法<<=. 但是,如果您提供自己的类型,则可以这样做。

def method(a:SpecialFloat, b:SpecialFloat, c:SpecialFloat)

implicit class SpecialFloat(v:Float) extends AnyVal {

  def < (other:Float) = ??? 
  def <= (other:Float) = ???
}

这样你就可以以任何你喜欢的方式实现这些方法。调用method(1f, 2f, 3f)会自动将它们转换为SpecialFloat实例(有关的更多信息extends AnyVal)。

于 2013-06-19T21:28:33.777 回答