Python支持"链式比较"的优雅语法,例如:
0 <= n < 256
Run Code Online (Sandbox Code Playgroud)
含义,
0 <= n and n < 256
Run Code Online (Sandbox Code Playgroud)
从语法上知道它是一种相当灵活的语言,是否可以在Scala中模拟这个功能?
丹尼尔的答案是全面的,实际上很难添加任何东西.由于他的回答是他提到的选择之一,我只想加上我的2美分,并以另一种方式提出一个非常短的解决方案.丹尼尔的描述:
理论上,您可以将其中一种方法的结果提供给另一种方法.我可以想到两种方法:
- <=返回一个对象,该对象同时具有接收的参数和比较结果,并且<使用这两个值.
CmpChain 将作为已经与最自由的最右边对象进行比较的累加器,以便我们可以将它与下一个对象进行比较:
class CmpChain[T <% Ordered[T]](val left: Boolean, x: T) {
def <(y: T) = new CmpChain(left && x < y, y)
def <=(y: T) = new CmpChain(left && x <= y, y)
// > and >= are analogous
def asBoolean = left
}
implicit def ordToCmpChain[T <% Ordered[T]](x: T) = new AnyRef {
def cmp = new CmpChain(true, x)
}
implicit def rToBoolean[T](cc: CmpChain[T]): Boolean = cc.asBoolean
Run Code Online (Sandbox Code Playgroud)
您可以将它用于任何有序类型,例如Ints或Doubles:
scala> (1.cmp < 2 < 3 <= 3 < 5).asBoolean
res0: Boolean = true
scala> (1.0.cmp < 2).asBoolean
res1: Boolean = true
scala> (2.0.cmp < 2).asBoolean
res2: Boolean = false
Run Code Online (Sandbox Code Playgroud)
隐式转换将产生Boolean它应该是的位置:
scala> val b: Boolean = 1.cmp < 2 < 3 < 3 <= 10
b: Boolean = false
Run Code Online (Sandbox Code Playgroud)
并不是的.需要记住的是,除了几个关键字之外,Scala中的所有内容都是对象的方法调用.
所以我们需要在一个对象上调用"<="和"<"方法,每个这样的方法都接收一个参数.那么,你需要四个对象,有三个显式对象,两个隐含对象 - 每个方法的结果.
理论上,您可以将其中一种方法的结果提供给另一种方法.我可以想到两种方法:
<=返回一个对象,该对象同时具有接收的参数和比较结果,并且<使用这两个值.
<=返回false或接收到的参数,并且<失败或与其他参数进行比较.这可以使用Either类或基于它的东西来完成.
事实上,这两种解决方案非常相似.
一个问题是这种比较运算符的消费者期望布尔结果.这实际上是最容易解决的问题,因为您可以将Either [Boolean,T]中的隐式定义为布尔值.
所以,从理论上讲,这是可能的.你可以用自己的一类来做.但是,您将如何改变已定义的现有方法?着名的Pimp My Class模式用于添加行为,而不是更改行为.
以下是第二个选项的实现:
object ChainedBooleans {
case class MyBoolean(flag: Either[Boolean, MyInt]) {
def &&(other: MyBoolean): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) other.flag else Left(false)
def <(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get < other else Left(false)
def >(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get > other else Left(false)
def ==(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get == other else Left(false)
def !=(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get != other else Left(false)
def <=(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get <= other else Left(false)
def >=(other: MyInt): Either[Boolean, MyInt] =
if (flag.isRight || flag.left.get) flag.right.get >= other else Left(false)
}
implicit def toMyBoolean(flag: Either[Boolean, MyInt]) = new MyBoolean(flag)
implicit def toBoolean(flag: Either[Boolean, MyInt]) =
flag.isRight || flag.left.get
case class MyInt(n: Int) {
def <(other: MyInt): Either[Boolean, MyInt] =
if (n < other.n) Right(other) else Left(false)
def ==(other: MyInt): Either[Boolean, MyInt] =
if (n == other.n) Right(other) else Left(false)
def !=(other: MyInt): Either[Boolean, MyInt] =
if (n != other.n) Right(other) else Left(false)
def <=(other: MyInt): Either[Boolean, MyInt] =
if (this < other || this == other) Right(other) else Left(false)
def >(other: MyInt): Either[Boolean, MyInt] =
if (n > other.n) Right(other) else Left(false)
def >=(other: MyInt): Either[Boolean, MyInt] =
if (this > other || this == other) Right(other) else Left(false)
}
implicit def toMyInt(n: Int) = MyInt(n)
}
Run Code Online (Sandbox Code Playgroud)
这是一个使用它的会话,显示可以做什么和不能做什么:
scala> import ChainedBooleans._
import ChainedBooleans._
scala> 2 < 5 < 7
<console>:14: error: no implicit argument matching parameter type Ordering[Any] was found.
2 < 5 < 7
^
scala> 2 < MyInt(5) < 7
res15: Either[Boolean,ChainedBooleans.MyInt] = Right(MyInt(7))
scala> 2 <= MyInt(5) < 7
res16: Either[Boolean,ChainedBooleans.MyInt] = Right(MyInt(7))
scala> 2 <= 5 < MyInt(7)
<console>:14: error: no implicit argument matching parameter type Ordering[ScalaObject] was found.
2 <= 5 < MyInt(7)
^
scala> MyInt(2) < 5 < 7
res18: Either[Boolean,ChainedBooleans.MyInt] = Right(MyInt(7))
scala> MyInt(2) <= 5 < 7
res19: Either[Boolean,ChainedBooleans.MyInt] = Right(MyInt(7))
scala> MyInt(2) <= 1 < 7
res20: Either[Boolean,ChainedBooleans.MyInt] = Left(false)
scala> MyInt(2) <= 7 < 7
res21: Either[Boolean,ChainedBooleans.MyInt] = Left(false)
scala> if (2 <= MyInt(5) < 7) println("It works!") else println("Ow, shucks!")
It works!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1033 次 |
| 最近记录: |