web-dev-qa-db-fra.com

Opérateur ternaire similaire à?:

J'essaie d'éviter de telles constructions:

val result = this.getClass.getSimpleName
if (result.endsWith("$")) result.init else result

Ok, dans cet exemple, les branches then et else sont simples, mais vous pouvez en imaginer des complexes . J'ai construit ce qui suit:

object TernaryOp {
  class Ternary[T](t: T) {
    def is[R](bte: BranchThenElse[T,R]) = if (bte.branch(t)) bte.then(t) else bte.elze(t)
  }
  class Branch[T](branch: T => Boolean) {
    def ?[R] (then: T => R) = new BranchThen(branch,then)
  }
  class BranchThen[T,R](val branch: T => Boolean, val then: T => R)
  class Elze[T,R](elze: T => R) {
    def :: (bt: BranchThen[T,R]) = new BranchThenElse(bt.branch,bt.then,elze)
  }
  class BranchThenElse[T,R](val branch: T => Boolean, val then: T => R, val elze: T => R)
  implicit def any2Ternary[T](t: T) = new Ternary(t)
  implicit def fct2Branch[T](branch: T => Boolean) = new Branch(branch)
  implicit def fct2Elze[T,R](elze: T => R) = new Elze(elze)
}

Défini cela, je peux remplacer l'exemple simple ci-dessus par:

this.getClass.getSimpleName is {s: String => s.endsWith("$")} ? {s: String => s.init} :: {s: String => s}

Mais comment puis-je me débarrasser du s: String =>? Je veux quelque chose comme ça:

this.getClass.getSimpleName is {_.endsWith("$")} ? {_.init} :: {identity}

J'imagine que le compilateur a besoin d'éléments supplémentaires pour déduire des types.

82
Peter Schmitz

Nous pouvons combiner Comment définir un opérateur ternaire dans Scala qui conserve les jetons menant? avec la réponse à L'option wrapper une valeur est-elle un bon modèle? obtenir

scala>   "Hi".getClass.getSimpleName |> {x => x.endsWith("$") ? x.init | x}
res0: String = String

scala> List.getClass.getSimpleName |> {x => x.endsWith("$") ? x.init | x}
res1: String = List

Est-ce adéquat pour vos besoins?

24
Rex Kerr

De Le blog Lambda de Tony Morris :

J'entends beaucoup cette question. Oui. Au lieu de c ? p : q, il s'agit de écrit if(c) p else q.

Cela peut ne pas être préférable. Peut-être aimeriez-vous l'écrire en utilisant le Même syntaxe que Java. Malheureusement, vous ne pouvez pas. C'est parce que : n'est pas un identifiant valide. Ne crains rien, | c'est! Voulez-vous vous contenter de cela?

c ? p | q

Ensuite, vous aurez besoin du code suivant. Remarquez l'appel par nom (=>) annotations sur les arguments. Cette stratégie d'évaluation est nécessaire pour réécrire correctement l’opérateur ternaire de Java. Cela ne peut pas être fait en Java lui-même.

case class Bool(b: Boolean) {   
  def ?[X](t: => X) = new {
    def |(f: => X) = if(b) t else f   
  } 
}

object Bool {   
  implicit def BooleanBool(b: Boolean) = Bool(b) 
}

Voici un exemple utilisant l'opérateur new que nous venons de définir:

object T {   val condition = true

  import Bool._

  // yay!   
  val x = condition ? "yes" | "no"
}

S'amuser ;)

112
Landei

Réponse de Rex Kerr exprimée en Scala de base:

"Hi".getClass.getSimpleName match {
  case x if x.endsWith("$") => x.init
  case x => x
}

bien que je ne sache pas quelle partie de la construction if – else vous souhaitez optimiser.

15
Debilski

Puisque les constructions if-else dans Scala renvoient une valeur, vous pouvez utiliser cette

val a = if (1 < 0) 1 else 2

Plus d'infos: https://alvinalexander.com/scala/scala-if-then-ternary-operator-cookbook-examples

6
Wouter

Puisque: par lui-même ne sera pas un opérateur valide sauf si vous êtes d'accord pour l'échapper toujours avec des ticks arrière :, vous pourriez utiliser un autre caractère, par exemple. "|" comme dans l'une des réponses ci-dessus. Mais que diriez-vous d'elvis avec une barbiche? ::

implicit class Question[T](predicate: => Boolean) {
  def ?(left: => T) = predicate -> left
}
implicit class Colon[R](right: => R) {
  def ::[L <% R](pair: (Boolean, L)): R = if (q._1) q._2 else right
}
val x = (5 % 2 == 0) ? 5 :: 4.5

Bien sûr, cela ne fonctionnera à nouveau pas si vos valeurs sont des listes, car elles ont elles-mêmes l'opérateur ::.

0
Ustaman Sangat