2012-01-04 39 views
6

Trong javascript, chúng ta có thể làm điều gì đó như:tương đương với toán tử javascript || trong scala

value = f1() || f2() || f3(); 

này sẽ gọi f1, và gán nó vào giá trị nếu kết quả không phải là null. chỉ khi kết quả là null, nó sẽ gọi f2 và gán giá trị đó nếu giá trị đó không phải là rỗng. ...

Một cách để đạt được điều này trong scala được đưa ra ở đây: How to make this first-not-null-result function more elegant/concise? tạo một hàm getFirstNNWithOption mà các cuộc gọi mỗi chức năng cho đến khi không null:

value = getFirstNNWithOption(List(f1 _, f2 _, f3 _)) 

Tuy nhiên, đây không phải là tốt đẹp như javascript || nhà điều hành, linh hoạt hơn. ví dụ:

value = f1() || f2(3) || f3(44, 'ddd') || value4; 

có cách nào để đạt được điều này trong scala không?

Trả lời

9

Tôi đang sử dụng đề xuất Option thay vì null.
Ví dụ:

class OptionPimp[T](o: Option[T]) { 
    def ||(opt: => Option[T]) = o orElse opt 
    def ||(t: => T) = o getOrElse t 
} 
implicit def optionPimp[T](o: Option[T]) = new OptionPimp(o) 

def f1(): Option[Int] = None 
def f2(): Option[Int] = None 
def f3(): Option[Int] = Some(3) 

val value1 = f1() || f2() || f3() || 4 // yields 3 
val value2 = f1() || f2()   || 4 // yields 4 
+0

Xin vui lòng đọc này, nơi chain được giải thích tốt. http://daily-scala.blogspot.com/2010/02/chaining-options-with-orelse.html –

+0

@dave điểm tốt, thx, được cập nhật! –

+0

Có thể là đáng giá để chunk một nội tuyến về điều này, nếu không tất cả những người gọi bằng các thông số tên ... –

11

Kể từ khi bạn đang sử dụng chức năng quay trở lại Option.

Giải pháp tốt nhất là nên sử dụng Chaining lựa chọn như nó được giải thích ở đây Option's chaining

Vì vậy, bạn sẽ làm gì

f1().orElse(f2()).orElse(f3()).orElse(Some(4)) 
+0

Đó là giải pháp tương tự so với @Peter Schmitz thực sự. W/o các pimp mẫu lib của tôi, giúp trong việc tránh các boilerplate Một số() cho chữ và có cái nhìn giống như bạn muốn. Vì vậy, tôi sẽ chỉ cần thêm như một bình luận một liên kết đến những gì tôi đề nghị. Đó vẫn là một điều phải đọc –

4

tôi khá nhiều ý kiến ​​giống như Andy, ngoại trừ tôi muốn sử dụng ký hiệu toán tử và sử dụng phương thức thích hợp để mặc định:

value = f1 orElse f2(3) orElse f3(44, 'ddd') getOrElse value4 
5

Nếu bạn đang sử dụng hàm này có thể trả về giá trị rỗng efine toán tử không hợp nhất:

class NullOption[A <: AnyRef](a: A) { 
    def |?|[B >: A](b: => B) = if (a ne null) a else b 
} 
implicit def null_handling[A <: AnyRef](a: A) = new NullOption(a) 

hoạt động giống như Javascript. (Tôi đã sử dụng |?| để tránh nhầm nó với logic lôgic hoặc, nhưng bạn có thể sử dụng || nếu bạn thích.) Điều này làm việc tốt hơn - gần giống như Option - nếu bạn thêm bản đồ có điều kiện (ở đây có tên ? --pick từ yêu thích của bạn hoặc ký hiệu):

class NullOption[A <: AnyRef](a: A) { 
    def |?|[B >: A](b: => B) = if (a ne null) a else b 
    def ?[C >: Null](f: A => C): C = if (a ne null) f(a) else null 
} 
implicit def null_handling[A <: AnyRef](a: A) = new NullOption(a) 

Sau đó, bạn có thể

scala> val s: String = null 
s: String = null 

scala> val t: String = "foo" 
t: String = foo 

scala> s?(_.toUpperCase) |?| t |?| { println("I am not executed"); "bar" } 
res4: java.lang.String = "foo" 

Tất nhiên, hệ thống kiểu của bạn sẽ không giúp bạn nhớ rằng bạn cần phải xử lý có-là-no-dữ liệu các trường hợp, nhưng nó có thể làm cho việc xử lý null dễ chịu hơn một chút (ít nhất là miễn là không có nguyên thủy, với các nguyên thủy, trả về n ull-hay-nguyên thủy không thực sự có ý nghĩa).

1

Với scala mới 2.10, bạn có thể sử dụng các lớp ngầm để cập nhật câu trả lời @PeterSchmitz, vì vậy bạn không cần xác định hàm chuyển đổi ngầm định.

implicit class OptionPimp[T](o: Option[T]) { 
    def ||(opt: => Option[T]) = o orElse opt 
    def ||(t: => T) = o getOrElse t 
} 

Tương tự cho Rex Kerr câu trả lời:

implicit class NullOption[A <: AnyRef](a: A) { 
    def |?|[B >: A](b: => B) = if (a ne null) a else b 
    def ?[C >: Null](f: A => C): C = if (a ne null) f(a) else null 
} 
Các vấn đề liên quan