2013-07-17 37 views
6

Ví dụ, nếu chúng ta có một phương pháp nhưLàm thế nào để Scala thực hiện trả về từ bên trong một biểu thức?

def find[A](xs: Seq[A], p: A => Boolean): Option[A] = { 
    xs.foreach(x => if (p(x)) return Some(x)); 
    None; 
} 

(tất nhiên có một chức năng thư viện cho điều này, đây chỉ là một ví dụ). Làm thế nào để thực hiện thoát foreach khi chức năng bên trong return s?

Hoặc trong

def foo(x: AnyRef): String = 
    process(x match { 
    case (s: String) => s; 
    case _   => return ""; 
    }) 

làm thế nào để tránh thực hiện chạy process khi return "" được ban hành?

+5

[Scala sử dụng ngoại lệ cho điều khiển luồng như thế này] (http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html) (từ khóa để tìm kiếm là 'NonLocalReturnControl '). Xem thêm * Đặc điểm ngôn ngữ Scala, mục 6.20 * –

+1

Xem thêm http://stackoverflow.com/a/9707524/247533 –

Trả lời

3

Các foo dụ phụ thuộc vào các

def process(s: String): String 
def process(s: => String): String 

nó được. Tôi giả định cái cũ, vì bạn đề xuất process không chạy. Đây chỉ là cách nó luôn hoạt động khi truyền một đối số - bạn làm công việc tạo đối số trước, sau đó gọi phương thức. Vì bạn chạy vào một return, thật dễ dàng: bạn chỉ cần gọi return thích hợp từ bytecode trong khi tạo đối số * và không bao giờ tiếp tục gọi phương thức. Vì vậy, chỉ là sự trở lại của địa phương.

Ví dụ find có liên quan nhiều hơn một chút. Chúng ta hãy thử một ví dụ tối đa đơn giản thúc đẩy bởi một foo mà đòi hỏi một sự trở lại không cục bộ:

class Nonlocal { 
    def pr(s: => String) = { println(s); "Printed" } 

    def foo(x: AnyRef): String = pr(x match { 
    case (s: String) => s; 
    case _   => return ""; 
    }) 
} 

Phần nội dung của foo tương đương với

import scala.runtime.NonLocalReturnControl 
val temp = new AnyRef 
try { 
    pr(x match { 
    case s: String => s 
    case _   => throw new NonLocalReturnControl(temp, "") 
    }) 
} 
catch { 
    case nlrc: NonLocalReturnControl[_] if (nlrc.key eq temp) => 
    nlrc.value.asInstanceOf[String] 
} 

Những điều quan trọng cần ghi nhận là một đối tượng trọng điểm được tạo nên rằng những điều này có thể được tùy ý lồng nhau mà không có clobbering nhau, và rằng NonLocalReturnControl mang lại giá trị chính xác trở lại. Không ngạc nhiên, đây không phải là chính xác rẻ so với chỉ trở về, nói, một Int. Nhưng vì nó tạo ra một ngoại lệ mà không có dấu vết ngăn xếp (an toàn, bởi vì nó không thể thoát được: khối catch được đảm bảo để nắm bắt nó), nó không phải là rằng xấu - là xấu như gọi hàm trig hoặc tổng hợp mảng với một vài chục mục.

Cũng lưu ý rằng pr chỉ nhận được một phần được thực thi trước khi ngoại lệ nhận được. Trong trường hợp này, nó không in bất cứ điều gì bởi vì điều đầu tiên nó làm là cố gắng sử dụng s để điền vào một chuỗi thực tế, nhưng sau đó nó chạm vào ngoại lệ mà giảm kiểm soát trở lại foo. (Vì vậy, bạn nhận được một chuỗi rỗng từ foo, nhưng bạn không in bất cứ điều gì.)

* Thực tế, trong bytecode nó có xu hướng là một bước nhảy đến cuối phương thức, với tải/trả lại ở đó. Mặc dù vậy, khái niệm không liên quan.

Các vấn đề liên quan