我正在编写一个生成Scala输出的代码生成器 .
我需要模仿一个三元运算符,使得令牌导致'?'保持不变 .
例如将表达式 c ? p : q
转换为 c something
. 简单 if(c) p else q
未通过我的标准,因为它需要在 c
之前放置 if(
.
我的第一次尝试(仍然使用上面的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 }
我喜欢第二个选项的整体外观,但有没有办法让它更简洁?
谢谢
4 回答
即使语法没有以预期的顺序进行评估 - 它将条件绑定到第一个选项! - 您可以像这样创建自己的三元运算符:
诀窍是将
?
解释为MakeIfTrue
对象上的方法,该对象将条件绑定到要在"true"情况下返回的对象 . 生成的IfTrue
对象现在使用|
方法作为评估条件的请求,如果条件为真则返回存储的true选项,如果是假则返回刚刚传入的true .请注意,我使用的东西如
=> A
而不仅仅是A
- by-name参数 - 为了不评估表达式,除非它只评估你实际需要的那一面(就像if语句一样) .让我们看看它的实际效果:
(P.S.为了避免与Actor库
?
混淆,你可能应该把它称为|?
之类的东西 . )让我们保持简单:
Java的:
斯卡拉:
除了简单,它是清晰和快速的,因为:不分配您不需要的对象,保持垃圾收集器不等式(因为它应该是),并更好地利用处理器缓存 .
你可以使用这样的东西
此代码将任何布尔值转换为具有名为
?
的方法的匿名类型 . 根据布尔值的不同,此方法将返回TernarySecond
或TernaryThird
. 它们都有一个名为>
的方法,它分别返回第二个操作数或第三个操作数 .三元运算符将我的改进添加到Rex Kerr和MichelKrämer的最佳实现中:
我使用Scala的新值类来避免拳击开销 .
在第2和第3个操作数上调用名称,以便仅评估所选的一个操作数 .
Michel在1st(布尔)操作数上调用by-value以避免按名称开销;它总是被评估 .
Rex的具体类,用于避免任何匿名类开销的条件 .
Michel对条件的评估,以确定构造哪个类以避免两个参数构造函数的开销 .
.
请注意,对
if else
的改进不仅仅是保存的6个字符 . 对于if
,else
,null
和true
,Scala IDE的关键字语法着色相同(例如紫色),在某些情况下会有更好的对比度(下面的语法着色没有显示当前在此网站上呈现的):