2009-12-30 2 views
34

Tôi muốn sử dụng val để khai báo nhiều biến như thế này:Tuyên bố nhiều biến trong Scala

val a = 1, b = 2, c = 3 

Nhưng vì lý do gì, đó là một lỗi cú pháp, vì vậy tôi đã kết thúc bằng cách sử dụng:

val a = 1 
val b = 2 
val c = 3 

hoặc

val a = 1; val b = 2; val c = 3; 

cá nhân tôi thấy cả hai lựa chọn quá dài dòng và loại xấu xí.

Có tùy chọn nào tốt hơn không?

Ngoài ra, tôi biết Scala là ngôn ngữ được suy nghĩ rất tốt, vậy tại sao cú pháp val a = 1, b = 2, c = 3 không được phép?

Trả lời

63

Câu trả lời tầm thường là để khai báo chúng như các bộ:

val (a, b, c) = (1, 2, 3) 

gì có thể là thú vị ở đây là điều này được dựa trên mô hình kết hợp. Điều thực sự xảy ra là bạn đang xây dựng một bộ dữ liệu và sau đó, thông qua đối sánh mẫu, gán giá trị cho a, bc.

Hãy xem xét một số ví dụ mẫu phù hợp khác để khám phá này một chút nữa:

val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r 
val DatePattern(year, month, day) = "2009-12-30" 
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100)) 
val head :: tail = List.range(1, 10) 

object ToInt { 
    def unapply(s: String) = try { 
    Some(s.toInt) 
    } catch { 
    case _ => None 
    } 
} 

val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01" 

Cũng giống như một mặt lưu ý, ví dụ rnd, đặc biệt, có thể được viết đơn giản hơn, và không có minh họa phù hợp với mô hình, như hình dưới đây.

val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100) 
+2

Điều đáng chú ý là 'val (a, b, c) = (1, 2, 3)' có vẻ là thành ngữ được chấp nhận chung cho nhiều bài tập, thích hợp hơn với các câu lệnh gán riêng biệt. Ít nhất, đó là ấn tượng của tôi đọc qua mã phát triển cộng đồng. –

+16

Cũng đáng chú ý là bạn có thể đặt nhiều vals cho cùng một giá trị với "val x, y, z = 42" trực quan. –

+2

Cũng có 'val seq @ Seq (a, b, c) = Seq (1,2,3)' không chỉ xác định các giá trị 'a',' b' và 'c', mà còn là' seqeunce 'seq '! – Mullefa

7

Có vẻ như để làm việc nếu bạn khai báo chúng trong một tuple

scala> val (y, z, e) = (1, 2, 45) 
y: Int = 1 
z: Int = 2 
e: Int = 45 
scala> e 
res1: Int = 45 

Mặc dù tôi có lẽ sẽ đi cho tuyên bố cá nhân. Đối với tôi, điều này có vẻ rõ ràng hơn:

val y = 1 
val z = 2 
val e = 45 

đặc biệt nếu các biến được đặt tên có ý nghĩa.

24

Câu trả lời của Daniel tóm tắt đúng cách để làm điều này, cũng như tại sao nó hoạt động. Vì anh ta đã bao quát góc đó, tôi sẽ cố trả lời câu hỏi rộng hơn của bạn (liên quan đến thiết kế ngôn ngữ) ...

Bất cứ nơi nào có thể, Scala cố gắng tránh thêm các tính năng ngôn ngữ để xử lý mọi thứ thông qua các cơ chế hiện có. Ví dụ: Scala không bao gồm tuyên bố break. Tuy nhiên, nó gần như không đáng kể để cuộn một trong những của riêng bạn như một thư viện:

case object BreakException extends RuntimeException 

def break = throw BreakException 

def breakable(body: =>Unit) = try { 
    body 
} catch { 
    case BreakException =>() 
} 

Điều này có thể được sử dụng theo cách sau:

breakable { 
    while (true) { 
    if (atTheEnd) { 
     break 
    } 

    // do something normally 
    } 
} 

(lưu ý: này được bao gồm trong thư viện chuẩn cho Scala 2.8)

Nhiều cú pháp chuyển nhượng như được phép theo các ngôn ngữ như Ruby (ví dụ: x = 1, y = 2, z = 3) rơi vào danh mục "cú pháp dự phòng". Khi Scala đã có một tính năng cho phép một mẫu cụ thể, nó tránh thêm một tính năng mới chỉ để xử lý một trường hợp đặc biệt của mẫu đó. Trong trường hợp này, Scala đã có kết hợp mẫu (một tính năng chung) có thể được sử dụng để xử lý nhiều phép gán (bằng cách sử dụng thủ thuật tuple được nêu trong các câu trả lời khác). Không cần thiết phải xử lý trường hợp đặc biệt đó theo cách riêng biệt.

Ngoài một chút khác biệt, cần lưu ý rằng cú pháp gán nhiều C (và do đó, Java) cũng là trường hợp đặc biệt của một tính năng tổng quát khác. Hãy xem xét:

int x = y = z = 1; 

Điều này khai thác thực tế rằng nhiệm vụ trả về giá trị được chỉ định bằng ngôn ngữ phái sinh C (cũng như thực tế nhiệm vụ đó là đúng liên kết). Đây không phải là trường hợp trong Scala. Trong Scala, nhiệm vụ trả về Unit. Trong khi điều này không có một số nhược điểm gây phiền nhiễu, nó là hợp lý về mặt lý thuyết vì nó nhấn mạnh tính chất tác dụng phụ của việc gán trực tiếp trong kiểu của nó.

+0

Câu trả lời hay, tôi ước tôi có thể chấp nhận hai câu trả lời = P. – Xavi

+0

Điều gì sẽ xảy ra nếu tôi muốn khai báo 2 biến nhưng không muốn gán chúng ngay lập tức? Giống như var a: MyClass, b: MyClass? –

+0

Tôi hy vọng bạn vẫn đang xem câu hỏi này. 'val x = y = z = 1' hoạt động trong Scala. Nó có vẻ là viết tắt của 'val x = 1; val y = 1; val z = 1; 'và không giống như phiên bản C. Nghĩa là, biểu thức bên phải của '=' được nhân bản và đánh giá nhiều lần. Đó có phải là cách nó được định nghĩa? – RussAbbott

15

Tôi sẽ thêm một quirk ở đây, bởi vì nó tự nhấn và có thể giúp người khác.

Khi sử dụng đối sánh mẫu, s.a. trong việc khai báo nhiều biến, không sử dụng tên Capital cho các biến. Chúng được coi là tên của các lớp trong khớp mẫu, và nó cũng được áp dụng ở đây.

val (A,B)= (10,20) // won't work 
    println(A) 

Thông báo lỗi không thực sự biết những gì đang xảy ra:

src/xxx.scala:6: error: not found: value A 
    val (A,B)= (10,20) 
    ^
src/xxx.scala:6: error: not found: value B 
    val (A,B)= (10,20) 
     ^
src/xxx.scala:7: error: not found: value A 
    println(A) 
     ^

tôi nghĩ '-ticking sẽ giải quyết vấn đề này nhưng vì một lý do dường như không (không chắc chắn, tại sao không):

val (`A`,`B`)= (10,20) 
    println(A) 

Vẫn còn lỗi giống như vậy.

Vui lòng nhận xét nếu bạn biết cách sử dụng mẫu khởi tạo tuple với tên biến vốn.

+3

Tôi detest rằng 'tính năng' của identifer đặt tên trong Scala. OK nếu bạn biết về nó, nhưng nó giữ cho mọi người vấp ngã (xem rất nhiều câu hỏi SO khác) và hoàn toàn bối rối cho đến khi bạn thu hẹp những gì đang xảy ra ... Nó smacks của Fortan của "Thiên Chúa là có thật - trừ khi tuyên bố số nguyên" –

+0

Tôi đồng ý. Và với 'đường' tương tự khác của Scala. Sẽ tốt nếu có cờ để loại trừ các phím tắt đó. Tuy nhiên ... vấn đề ban đầu của tôi vẫn còn. Có cách nào để sử dụng tên biến CAPITAL với khởi tạo tuple? – akauppi

+1

Chỉ cần nhấn bản thân này. May mắn thay googling 'scala tuple gán val "không tìm thấy"' dẫn đến câu trả lời này, tránh cho tôi nhiều bamboozlement. – timday

4

Nếu tất cả các biến của bạn cùng loại và có cùng giá trị ban đầu, bạn có thể thực hiện việc này.

val a, b, c: Int = 0; 
+3

Lưu ý rằng '0' có thực sự là một hàm. Thay thế nó bằng một cái gì đó như Math.random cung cấp hai giá trị khác nhau. – akauppi