2013-02-18 26 views
43

Nói rằng tôi đang viết một phương pháp khuyến nôngCác lớp ngầm có nên mở rộng AnyVal không?

implicit class EnhancedFoo(foo: Foo) { 
    def bar() { /* ... */ } 
} 

nên bạn luôn bao gồm extends AnyVal trong defininition lớp học? Trong hoàn cảnh nào bạn sẽ không muốn tạo ra một lớp ngầm định một lớp giá trị?

Trả lời

38

Hãy nhìn vào limitations listed for value classes và suy nghĩ khi họ có thể không phù hợp cho các lớp ẩn:

  1. "phải chỉ có một nhà xây dựng chính với chính xác một cộng đồng, tham số val có loại không phải là một lớp học giá trị. " Vì vậy, nếu lớp bạn đang gói là chính nó một lớp giá trị, bạn không thể sử dụng một implicit class như là một wrapper, nhưng bạn có thể làm điều này:

    // wrapped class 
    class Meters(val value: Int) extends AnyVal { ... } 
    
    // wrapper 
    class RichMeters(val value: Int) extends AnyVal { ... } 
    
    object RichMeters { 
        implicit def wrap(m: Meter) = new RichMeter(m.value) 
    } 
    

    Nếu wrapper của bạn có các thông số ngầm là tốt, bạn có thể thử di chuyển chúng đến các khai báo phương thức. I E. thay vì

    implicit class RichFoo[T](foo: Foo[T])(implicit ord: Ordering[T]) { 
        def bar(otherFoo: Foo[T]) = // something using ord 
    } 
    

    bạn có

    implicit class RichFoo[T](foo: Foo[T]) extends AnyVal { 
        def bar(otherFoo: Foo[T])(implicit ord: Ordering[T]) = // something using ord 
    } 
    
  2. "có thể không có tham số kiểu đặc biệt." Bạn có thể muốn trình bao bọc được chuyên môn hóa khi gói một lớp mà chính nó có các tham số kiểu đặc biệt.

  3. "có thể không có các lớp, đặc điểm hoặc đối tượng địa phương lồng nhau hoặc" Một lần nữa, một thứ có thể hữu ích cho việc triển khai trình bao bọc.
  4. "không được xác định phương thức equals hoặc hashCode". Không liên quan, vì các lớp ngầm cũng không nên có equals/hashCode.
  5. "phải là một lớp cấp cao nhất hoặc là thành viên của đối tượng có thể truy cập tĩnh" Đây cũng là nơi bạn thường định nghĩa các lớp ẩn, nhưng không bắt buộc.
  6. "chỉ có thể có defs như các thành viên. Đặc biệt, nó không thể có lười biếng vals, vars, hoặc vals là thành viên." Các lớp ngầm định có thể có tất cả các lớp đó, mặc dù tôi không thể nghĩ ra một số lần sử dụng hợp lý cho var s hoặc lazy val s.
  7. "không thể được mở rộng bởi một lớp khác". Một lần nữa, các lớp ngầm có thể được mở rộng, nhưng có lẽ không có lý do chính đáng để.

Ngoài ra, làm cho lớp tiềm ẩn của bạn một lớp giá trị có thể có thể thay đổi một số hành vi của mã bằng cách sử dụng sự phản chiếu, nhưng phản ánh không thường thấy các lớp ngầm định.

Nếu lớp ngầm của bạn đáp ứng tất cả các giới hạn đó, tôi không thể nghĩ ra lý do để không biến nó trở thành một lớp giá trị.

+0

fwiw, đây là trường hợp sử dụng cho 'lazy val' bên trong' lớp ẩn ': https: //gist.github.com/SethTisue/8977033. May mắn thay có một cách giải quyết dễ dàng (cũng được thể hiện trong ý chính). –

+1

"Tôi không thể nghĩ ra một lý do nào để không biến nó trở thành một lớp giá trị." - bởi vì nó mất tập trung nhưng không mang lại lợi ích gì. Tôi đã không thể tái tạo các lợi ích bộ nhớ được giả định của "extends AnyVal" các lớp ngầm định trong các bài kiểm tra của tôi. Bạn có một trích dẫn cho những lợi ích? – Rich

+0

Tài liệu này vẫn đề xuất, nhưng tôi không thể đo lường bất kỳ lợi ích nào trong các bài kiểm tra của mình. http://docs.scala-lang.org/overviews/core/value-classes.html – Rich

2

Tôi cảm thấy bạn đang bối rối Value Classes với Implicit Classes. Bạn hiếm khi mở rộng bất cứ điều gì khi xác định Lớp học ngầm định để tăng cường trong khi Lớp giá trị phải mở rộng AnyVal.

+11

Tôi có thể thuật lại câu hỏi là "lớp ngầm sẽ luôn là lớp giá trị?". Tại sao bạn không muốn lớp ngầm của bạn trở thành một lớp giá trị, nếu nó loại bỏ chi phí tạo ra cá thể? –

+2

Lớp giá trị có nhiều hạn chế. Nếu chúng phù hợp, chắc chắn, hãy sử dụng chúng để tăng cường. –

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