Я пишу генератор кода, который производит вывод Scala.
Я должен эмулировать тернарный оператор таким способом который маркерное продвижение до'?' останьтесь неповрежденными.
например, преобразуйте выражение 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 }
Мне нравится общий вид второй опции, но есть ли способ сделать это менее подробным?
Спасибо
Несмотря на то, что синтаксис не вычисляется в ожидаемом порядке - он связывает условие с первым вариантом! - вы можете создать свой собственный тернарный оператор следующим образом:
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
, который привязывает условие к объекту для возврата в «истинном» случае. Результирующий объект 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
(PS Чтобы избежать путаницы с библиотекой Actor ?
, вам, вероятно, следует назвать ее как-то иначе, например |?
.)
Вы можете использовать что-то вроде этого
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
. У них обоих есть метод под названием >
, который возвращает второй или третий операнд соответственно.