Tại sao Scala đã trở lại nhưng không phá vỡ và tiếp tục


22

Scala không có breakhoặc continue, vì vậy một số hành vi vòng lặp cần thêm một chút suy nghĩ.

Kết thúc vòng lặp sớm đòi hỏi đệ quy đuôi, ngoại lệ hoặc scala.util.control.Breaks(sử dụng ngoại lệ).

Lý do cho điều này là, giống như goto, chúng là các cấu trúc dòng chảy che khuất dòng chảy và có thể được thực hiện theo những cách tốt hơn, ít gây ngạc nhiên hơn.

Nhưng có vẻ như những lý lẽ tương tự có thể được sử dụng cho return.

Tại sao Scala cố tình bỏ qua breakcontinue, nhưng không phải return?


1
Tôi có thể tưởng tượng rằng các tác giả của ngôn ngữ xem xét đệ quy đuôi như các cách để xây dựng lặp. Tôi có thể tưởng tượng điều đó breakcontinuecần một số máy móc dọn dẹp bổ sung. OTOH returnlà một cách để chấm dứt một cách có trật tự một chức năng, và bất kỳ máy móc dọn dẹp nào cũng đã có sẵn.
9000

1
breakable { for { break; } }nhưng một suy nghĩ lại, và có khả năng xa hiệu quả.
Eggen

Bởi vì với các chức năng thực sự không có lý do cho nó. Nó giống nhau ở trăn. Mỗi lần bạn sử dụng một vòng lặp for với break, thay vào đó bạn có thể viết một hàm, đặt vòng lặp của bạn vào hàm và sử dụng return. Tôi không thể nghĩ về một tình huống mà đây không phải là một ý tưởng tốt liên quan đến mã sạch. Đối với hiệu suất, sạch sẽ có thể tốt hơn, nhưng hiệu suất không có ưu tiên cao nhất trong scala.
valenterry

2
Câu hỏi này có vẻ như đã có câu trả lời ở đây: stackoverflow.com/questions/3770989/ triệt
Michael Shaw

3
@PaulDraper: Câu trả lời cho breakcontinuecó trong câu hỏi của bạn và trong liên kết trong câu hỏi của bạn. Câu hỏi cho returnchính xác là câu hỏi tôi liên kết là gì, và đã được trả lời, ít nhất là trong câu trả lời được bình chọn hàng đầu, được chấp nhận. Nếu hai câu trả lời ghép lại không trả lời câu hỏi của bạn, có lẽ bạn có thể chỉnh sửa câu hỏi để làm rõ câu hỏi.
Michael Shaw

Câu trả lời:


16

Phá vỡ và tiếp tục:

Trong một cuộc nói chuyện về Scala , Martin Oderky đã đưa ra 3 lý do để không bao gồm nghỉ hoặc tiếp tục trên slide 22:

  • Họ là một chút cấp bách; sử dụng tốt hơn nhiều chức năng nhỏ hơn.
  • Vấn đề làm thế nào để tương tác với đóng cửa.
  • Họ không cần thiết!

Và sau đó ông nói, "Chúng tôi có thể hỗ trợ họ hoàn toàn trong các thư viện." Trên slide 23, anh ta đưa ra mã thực hiện break. Mặc dù tôi hoàn toàn không biết Scala đủ chắc chắn, nhưng có vẻ như đoạn trích ngắn trên slide đó là tất cả những gì cần thiết để thực hiện breakvà điều đó continuecó thể được thực hiện trong mã ngắn tương tự.

Có thể thực hiện những thứ như thế này trong các thư viện đơn giản hóa ngôn ngữ cốt lõi.

Trong 'Lập trình trong Scala, Ấn bản thứ hai', của Martin Oderky, Lex Spoon và Bill Venners, lời giải thích sau đây được đưa ra:

Bạn có thể nhận thấy rằng không có đề cập đến breakhoặc continue. Scala loại bỏ các lệnh này vì chúng không kết hợp tốt với nghĩa đen của hàm ... Rõ ràng điều gì continuecó nghĩa bên trong một whilevòng lặp, nhưng ý nghĩa của nó bên trong một hàm nghĩa là gì? ... Có rất nhiều cách để chương trình không breakcontinue, và nếu bạn tận dụng lợi thế của literals chức năng, những lựa chọn thay thế thường có thể là ngắn hơn so với mã gốc.

Trở về:

Trả về có thể được coi là một chút bắt buộc trong phong cách, vì return là một động từ, một lệnh để làm một cái gì đó. Nhưng chúng cũng có thể được nhìn thấy theo cách hoàn toàn có chức năng / khai báo: chúng xác định giá trị trả về của hàm là gì (ngay cả khi, trong một hàm có nhiều trả về, chúng chỉ đưa ra một định nghĩa một phần).

Trong cùng một cuốn sách, họ nói như sau về return:

Trong trường hợp không có bất kỳ returncâu lệnh rõ ràng nào , một phương thức Scala trả về giá trị cuối cùng được tính theo phương thức. Phong cách được đề xuất cho các phương thức trên thực tế là để tránh có các returncâu lệnh rõ ràng và đặc biệt là nhiều câu lệnh. Thay vào đó, hãy nghĩ về mỗi phương thức như một biểu thức mang lại một giá trị, được trả về.

Các phương thức kết thúc và trả về một giá trị, ngay cả khi một returncâu lệnh không được sử dụng, do đó không thể có vấn đề với các bao đóng, vì nếu không các bao đóng sẽ không có thời gian làm việc.

Cũng có thể không có vấn đề chia lưới tốt với hàm chữ, vì hàm này phải trả về một giá trị nào.


2
Về lợi nhuận, dường như có một số nguy hiểm nhẹ: tpolecat.github.io/2014/05/09/return.html
bbarker

0

Tôi nghĩ rằng các câu trả lời trước làm công bằng cho các vấn đề xác định ngữ nghĩa cho breakhoặc continuetheo cách nói rộng rãi ngôn ngữ cho Scala, với bối cảnh tương đối không bị ràng buộc.

Tôi đã viết một thư viện nhỏ xác định breakcontinuetrong một bối cảnh hạn chế hơn: lặp lại các chuỗi thông qua Scala để hiểu. Bằng cách tập trung vào bối cảnh đó, tôi tin rằng ngữ nghĩa trở nên rõ ràng và dễ lý luận.

Thư viện có sẵn tại đây: https://github.com/erikerlandson/breakable

Đây là một ví dụ đơn giản về những gì nó trông giống như trong mã:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.