2009-03-23 34 views
31

Xuất thân từ một nền Java, tôi quen với thực tế phổ biến đối phó với các bộ sưu tập: rõ ràng là sẽ có ngoại lệ nhưng mã này thường sẽ trông như thế:Scala bộ sưu tập tiêu chuẩn thực hành

public class MyClass { 
    private Set<String> mySet; 

    public void init() { 
    Set<String> s = new LinkedHashSet<String>(); 
    s.add("Hello"); 
    s.add("World"); 
    mySet = Collections.unmodifiableSet(s); 
    } 
} 

tôi phải thú nhận rằng Tôi hơi bối rối bởi rất nhiều lựa chọn ở Scala. Có:

  • scala.List (và Seq)
  • scala.collections.Set (và Map)
  • scala.collection.immutable.Set (và Map, Stack nhưng không List)
  • scala.collection.mutable.Set (và Map, Buffer nhưng không List)
  • scala.collection.jcl

Vì vậy, câu hỏi!

  1. Tại sao ListSeq định nghĩa trong gói scala và không scala.collection (mặc dù triển khai của Seq là trong bộ sưu tập phụ gói)?
  2. Cơ chế tiêu chuẩn để khởi tạo một bộ sưu tập là gì và sau đó đóng băng nó (trong Java đạt được bằng cách gói trong một unmodifiable)?
  3. Tại sao một số loại bộ sưu tập (ví dụ: MultiMap) chỉ được định nghĩa là có thể thay đổi? (Không có bất biến MultiMap)?

Tôi đã đọc số excellent series on scala collections của Daniel Spiewak và tôi vẫn bối rối về cách người ta thực sự sử dụng chúng trong thực tế. Sau đây dường như hơi khó sử dụng do tờ khai trọn gói được thực thi:

class MyScala { 
    var mySet: scala.collection.Set[String] = null 

    def init(): Unit = { 
    val s = scala.collection.mutable.Set.empty[String] 
    s + "Hello" 
    s + "World" 
    mySet = scala.collection.immutable.Set(s : _ *) 

    } 
} 

Mặc dù cho là đây là chính xác hơn so với phiên bản Java như bộ sưu tập bất biến không thể thay đổi (như trong trường hợp Java, nơi mà các bộ sưu tập cơ bản có thể được thay đổi bên dưới vỏ bọc unmodifiable)

Trả lời

26

Tại sao Danh sách và Seq được định nghĩa trong gói scala chứ không phải scala.collection (mặc dù triển khai Seq nằm trong gói phụ thu)?

Vì chúng được coi là hữu ích nói chung nên chúng được nhập tự động vào tất cả các chương trình thông qua các từ đồng nghĩa trong scala.Predef.

Cơ chế tiêu chuẩn để khởi tạo bộ sưu tập là gì và sau đó làm đông lạnh (trong Java có thể đạt được bằng cách đóng gói trong không thể sửa đổi)?

Java không có cơ chế để đóng băng bộ sưu tập. Nó chỉ có một thành ngữ để gói bộ sưu tập (vẫn có thể sửa đổi) trong một trình bao bọc mà ném một ngoại lệ.Thành ngữ phù hợp trong Scala là sao chép một bộ sưu tập có thể thay đổi thành một bộ sưu tập không thể thay đổi - có thể sử dụng: _ *

Tại sao một số loại bộ sưu tập (ví dụ: MultiMap) chỉ được định nghĩa là có thể thay đổi? (Không có MultiMap bất biến)?

Nhóm/cộng đồng chưa đến đó. Chi nhánh 2.7 nhìn thấy một loạt các bổ sung và 2.8 được dự kiến ​​sẽ có nhiều hơn nữa.

Sau đây dường như hơi khó sử dụng do tờ khai trọn gói được thực thi:

Scala phép bí danh nhập khẩu vì vậy nó luôn ít tiết hơn Java trong lĩnh vực này (xem ví dụ java.util.Date và java .sql.Date - sử dụng cả lực lượng từ một đến có đủ điều kiện)

import scala.collection.{Set => ISet} 
import scala.collection.mutable.{Set => MSet} 

class MyScala { 
    var mySet: ISet[String] = null 

    def init(): Unit = { 
    val s = MSet.empty[String] 
    s + "Hello" 
    s + "World" 
    mySet = Set(s : _ *) 
    } 
} 

Tất nhiên, bạn sẽ thực sự chỉ cần viết init như def init() { mySet = Set("Hello", "World")} và lưu tất cả những rắc rối hoặc tốt hơn nhưng chỉ cần đặt nó trong constructor var mySet : ISet[String] = Set("Hello", "World")

+1

Tôi đoán khả năng vòng lặp của nó thông qua thứ gì đó và thêm nó vào tập hợp, thay vì chỉ là một nhóm giá trị. – runT1ME

4

Một vài suy nghĩ ngẫu nhiên:

  1. tôi không bao giờ sử dụng null, tôi sử dụng Option, mà sau đó sẽ quăng một lỗi đàng hoàng. Thực tiễn này đã loại bỏ một cơ hội tonNullPointerException và buộc mọi người viết các lỗi phong nha.
  2. Cố gắng tránh xem xét nội dung "có thể thay đổi" trừ khi bạn thực sự cần.

Vì vậy, mất cơ bản của tôi về dụ scala của bạn, nơi bạn có thể khởi tạo các thiết lập sau đó, là

class MyScala { 
    private var lateBoundSet:Option[ Set[ String ] ] = None 
    def mySet = lateBoundSet.getOrElse(error("You didn't call init!")) 

    def init { 
    lateBoundSet = Some(Set("Hello", "World")) 
    } 
} 

Tôi đã ở trên một giọt nước mắt gần đây xung quanh văn phòng. "null là ác!"

3

Lưu ý rằng có thể có một số mâu thuẫn trong API bộ sưu tập Scala trong phiên bản hiện tại; cho Scala 2.8 (sẽ được phát hành vào cuối năm 2009), API bộ sưu tập đang được đại tu để làm cho nó phù hợp hơn và linh hoạt hơn.

Xem bài viết này trên trang web Scala: http://www.scala-lang.org/node/2060

Để thêm vào ví dụ Tristan Juricek với một lateBoundSet: Scala có một cơ chế tích hợp để khởi tạo lười biếng, sử dụng "lười biếng" keyword:

class MyClass { 
    lazy val mySet = Set("Hello", "World") 
} 

Bằng cách này, mySet sẽ được khởi tạo vào lần sử dụng đầu tiên, thay vì ngay lập tức khi tạo một phiên bản MyClass mới.

7

Bộ sưu tập có thể thay đổi đôi khi hữu ích (mặc dù tôi đồng ý rằng bạn nên luôn luôn xem xét những cái bất biến trước). Nếu sử dụng chúng, tôi có xu hướng để viết

import scala.collection.mutable 

ở phía trên cùng của tập tin, và (ví dụ):

val cache = new mutable.HashMap[String, Int] 

trong mã của tôi. Nó có nghĩa là bạn chỉ phải viết “mutable.HashMap” chứ không phải scala.collection.mutable.HashMap ”. Là người bình luận ở trên được đề cập, bạn có thể remap tên trong quá trình nhập (ví dụ: “nhập scala.collection.mutable. {HashMap => MMap}”), nhưng:

  1. Tôi không thích xé tên, để rõ ràng hơn tôi đang sử dụng những lớp nào và
  2. Tôi sử dụng 'có thể thay đổi' hiếm khi đủ rằng có "mutable.ClassName" trong nguồn của tôi không phải là một gánh nặng quá mức.

(Ngoài ra, tôi cũng có thể lặp lại bình luận 'tránh null'. Điều này làm cho mã trở nên mạnh mẽ và dễ hiểu hơn. Tôi thấy rằng tôi thậm chí không phải sử dụng Tùy chọn nhiều như bạn mong đợi .)

+0

Tôi thích quy ước đặt tên đó. Bạn nên đóng góp tại đây: http://groups.google.com/group/liftweb/browse_thread/thread/4460656773dc8729/47359c9e7cd08c80 – Trenton

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