我正在编写一个生成Scala输出的代码生成器。
我需要模仿三元运算符,使得令牌达到'?'保持完整。
e.g。将表达式c ? p : q
转换为c something
。简单的if(c) p else q
未达到我的条件,因为它需要在if(
之前加c
。
我的第一次尝试(仍然使用上面的c / p / q)是
c match { case(true) => p; case _ => q }
我找到的另一个选项是:
class ternary(val g: Boolean => Any) { def |: (b:Boolean) = g(b) } implicit def autoTernary (g: Boolean => Any): ternary = new ternary(g)
允许我写:
c |: { b: Boolean => if(b) p else q }
我喜欢第二个选项的整体外观,但有没有办法让它更简洁?
由于
答案 0 :(得分:14)
即使语法没有以预期的顺序进行评估 - 它将条件绑定到第一个选项! - 你可以像这样制作自己的三元运算符:
class IfTrue[A](b: => Boolean, t: => A) { def |(f: => A) = if (b) t else f }
class MakeIfTrue(b: => Boolean) { def ?[A](t: => A) = new IfTrue[A](b,t) }
implicit def autoMakeIfTrue(b: => Boolean) = new MakeIfTrue(b)
诀窍是将?
解释为MakeIfTrue
对象上的一种方法,该方法将条件绑定到对象以在“true”情况下返回。生成的IfTrue
对象现在使用|
方法作为评估条件的请求,如果条件为真,则返回存储的true选项,如果条件为假,则返回刚刚传入的选项。
请注意,我使用=> A
之类的东西而不仅仅是A
- 名字参数 - 以便不评估表达式,除非它实际使用。因此,您只会评估您实际需要的那一方(就像if语句一样)。
让我们看看它的实际效果:
scala> List(1,3,2).isEmpty ? "Empty" | "Nonempty"
res0: java.lang.String = Nonempty
scala> (4*4 > 14) ? true | false
res1: Boolean = true
scala> class Scream(s: String) { println(s.toUpperCase + "!!!!") }
defined class Scream
scala> true ? new Scream("true") | new Scream("false")
TRUE!!!!
res3: Scream = Scream@1ccbdf7
(P.S。为避免与Actor库?
混淆,您可能应该将其称为|?
之类的其他内容。)
答案 1 :(得分:14)
让我们保持简单:
爪哇:
tmp = (a > b) ? a : b;
Scala的:
tmp = if (a > b) a else b
除了简单之外,它是清晰而快速的,因为:不要分配你不需要的对象,使垃圾收集器不受方程式影响(因为它应该是这样)并且更好地利用处理器缓存。
答案 2 :(得分:4)
你可以使用这样的东西
sealed trait TernaryOperand[A] {
def >(q: => A): A
}
case class TernarySecond[A](val p: A) extends TernaryOperand[A] {
def >(q: => A) = p
}
case class TernaryThird[A]() extends TernaryOperand[A] {
def >(q: => A) = q
}
implicit def ternary(c: Boolean) = new {
def ?[A](p: => A): TernaryOperand[A] = if (c) TernarySecond(p) else TernaryThird()
}
val s1 = true ? "a" > "b"
println(s1) //will print "a"
val s2 = false ? "a" > "b"
println(s2) //will print "b"
此代码将任何布尔值转换为具有名为?
的方法的匿名类型。根据布尔值的不同,此方法将返回TernarySecond
或TernaryThird
。它们都有一个名为>
的方法,它分别返回第二个操作数或第三个操作数。
答案 3 :(得分:0)
三元运算符将我的改进添加到Rex Kerr和MichelKrämer的最佳实现中:
sealed trait TernaryResult[T] extends Any {
def |(op3: => T): T
}
class Ternary2ndOperand[T](val op2: T) extends AnyVal with TernaryResult[T] {
def |(op3: => T) = op2
}
class Ternary3rdOperand[T](val op2: T) extends AnyVal with TernaryResult[T] {
def |(op3: => T) = op3
}
class Ternary(val op1:Boolean) extends AnyVal {
def ?[A](op2: => A): TernaryResult[A] = if (op1) new Ternary2ndOperand(op2) else new Ternary3rdOperand(op2)
}
object Ternary {
implicit def toTernary(condition: Boolean) = new Ternary(condition)
}
请注意,if else
的改进不仅仅是保存的6个字符。对于if
,else
,null
和true
,Scala IDE对关键字的语法着色相同(例如紫色),在某些情况下会有更好的对比度(不是下面的语法着色显示为当前在此网站上呈现的内容):
if (cond) true else null
cond ? true | null