Câu hỏi Ternary Operator tương tự như?:


Tôi đang cố gắng tránh các cấu trúc như thế này:

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

Ok, trong ví dụ này then và else nhánh rất đơn giản, nhưng bạn có thể tạo hình ảnh phức tạp. Tôi đã xây dựng như sau:

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)
}

Xác định rằng, tôi có thể thay thế ví dụ đơn giản trên bằng:

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

Nhưng làm sao tôi có thể loại bỏ s: String =>? Tôi muốn một cái gì đó như thế:

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

Tôi đoán trình biên dịch cần thêm công cụ để suy ra các loại.


76
2018-02-09 16:20


gốc


Vì tôi không thực sự có câu trả lời này - lý do bạn gặp rắc rối là suy luận kiểu hoạt động tốt nhất từ ​​trái sang phải, nhưng bạn liên kết các thẻ của bạn với nhau từ phải sang trái vì ưu tiên toán tử. Nếu bạn làm cho tất cả các từ tuyên bố của bạn (với cùng một ưu tiên) và thay đổi cách mọi thứ nhóm lại với nhau, bạn sẽ nhận được suy luận mà bạn muốn. (Nghĩa là bạn sẽ có HasIs, IsWithCondition, ConditionAndTrueCase các lớp sẽ xây dựng các phần của biểu thức từ trái sang phải.) - Rex Kerr
Tôi vô thức suy đoán cách suy luận kiểu từ trái sang phải, nhưng bị mắc kẹt với ưu tiên toán tử và tính kết hợp của tên phương thức, đặc biệt là bắt đầu bằng ? trước bất kỳ char alphanum nào khác làm tên phương thức đầu tiên là char và a : để kết hợp trái. Vì vậy, tôi phải suy nghĩ lại về các tên phương thức mới để có được suy luận kiểu làm việc từ trái sang phải. cảm ơn! - Peter Schmitz


Các câu trả lời:


Chúng ta có thể kết hợp Làm thế nào để xác định một toán tử bậc ba trong Scala mà giữ gìn mã thông báo hàng đầu? với câu trả lời cho Tùy chọn có bao gồm một giá trị một mẫu tốt không? để có được

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

Điều này có phù hợp với nhu cầu của bạn không?


21
2018-02-09 16:45



Thats rất gần với những gì tôi có trong tâm trí. cách tiếp cận tốt đẹp. Tôi sẽ nghĩ về điều đó. Lý do của tôi để tránh mã đầu tiên là súc tích hơn trong việc không có tạm thời valcho một sau if-statement: Làm cho nó dễ hiểu trong một dòng, giống như một trong những có nó trong tâm trí. - Peter Schmitz


Từ Blog Lambda của Tony Morris:

Tôi nghe câu hỏi này rất nhiều. Có nó. Thay vì c ? p : q, nó là   bằng văn bản if(c) p else q.

Điều này có thể không thích hợp hơn. Có lẽ bạn muốn viết nó bằng cách sử dụng   cùng cú pháp với Java. Đáng buồn thay, bạn không thể. Điều này là bởi vì : Không phải là   số nhận dạng hợp lệ. Đừng sợ, | Là! Bạn sẽ giải quyết cho điều này?

c ? p | q

Sau đó, bạn sẽ cần mã sau. Hãy chú ý đến tên gọi (=>)   chú thích trên các đối số. Chiến lược đánh giá này là bắt buộc để   viết lại chính xác toán tử ternary của Java. Điều này không thể được thực hiện trong Java   chinh no.

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) 
}

Đây là một ví dụ sử dụng toán tử mới mà chúng ta vừa định nghĩa:

object T {   val condition = true

  import Bool._

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

Chúc vui vẻ ;)


104
2018-02-09 19:06



có, tôi đã thấy điều này trước đây, nhưng sự khác biệt là, rằng tôi có giá trị (được đánh giá) của biểu thức đầu tiên của tôi như một đối số trong then và else mệnh đề. - Peter Schmitz
@Imre: Tôi đã sửa liên kết và sao chép nội dung. - Landei
Tôi lấy cái if(c) p else q cách tiếp cận ... thiếu niềng răng khiến tôi cảm thấy khó chịu nhưng đó chỉ là một thứ phong cách - rjohnston


Câu trả lời của Rex Kerr thể hiện trong Scala cơ bản:

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

mặc dù tôi không chắc chắn phần nào của cấu trúc if – else bạn muốn tối ưu hóa.


14
2018-02-09 16:52



rất thẳng. đôi khi một người quên về các câu lệnh về trường hợp / trường hợp sử dụng hàng ngày. Tôi chỉ dính vào một dòng thứ ba if then else thành ngữ, nhưng đó thực sự là một cách dễ hiểu để giải quyết. - Peter Schmitz
Pattern Matching quy mô dễ dàng đến hơn hai nhánh. - Raphael


Vì nếu các công trình xây dựng khác trong Scala trả về một giá trị, bạn có thể sử dụng

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

Thêm thông tin: https://alvinalexander.com/scala/scala-if-then-ternary-operator-cookbook-examples


2
2018-02-13 13:53





Vì: bản thân nó sẽ không phải là một toán tử hợp lệ trừ khi bạn đồng ý với việc luôn luôn thoát nó bằng các dấu tick :, bạn có thể đi với một nhân vật khác, ví dụ: "|" như một trong những câu trả lời ở trên. Nhưng làm thế nào về elvis với một goatee? ::

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

Tất nhiên điều này một lần nữa sẽ không hoạt động nếu bạn có giá trị là danh sách, vì họ có :: operator mình.


0
2018-01-25 20:43