2011-10-06 45 views
5

Gần đây tôi được hỏi về phím composite trong các bản đồ trong clojure: How can you implement Composite keys in clojure? ...Clojure tương đương với Overriding "bằng" trong java là gì?

Câu trả lời là họ làm việc tương tự như phím java - nếu một cái gì đó đè "bằng", sau đó nó có thể được sử dụng một cách hiệu quả như một chìa khóa.

Tôi đã tự hỏi: Có các macro cho phép chúng tôi ghi đè "bằng" cho cấu trúc dữ liệu tùy chỉnh không? Ví dụ: giả sử tôi muốn sử dụng Bản đồ làm khóa và xác định tính duy nhất là "nếu bản đồ này chứa 2 hoặc nhiều phần tử chung với một bản đồ khác, chúng giống nhau". Làm thế nào tôi có thể ghi đè lên hành vi mặc định của bản đồ?

Trong java, tôi thấy thiết bị này khá mạnh mẽ khi tạo bản đồ tốc độ cao với hàng nghìn hạt làm chìa khóa.

Trả lời

4

Nó không phải là bộ sưu tập clojure ghi đè bằng; trọng số bằng nhau xảy ra gần như ở khắp mọi nơi bạn đang làm một cái gì đó thú vị. Các kiểu Clojure cung cấp một sự thực thi bằng các từ khóa được dự định là nhất quán cho toàn bộ ngôn ngữ (được cho là theo cách mà các giá trị bằng Java được dự định sẽ được sử dụng). Điều đó có nghĩa là những thứ "bình đẳng" phải là các mục số ít trong bộ và các phím số trong bản đồ, luôn là ở mọi nơi. Thiết kế ngôn ngữ phụ thuộc vào điều đó. Clojure 1.3 đã thực hiện một số thay đổi tương thích không lặp lại rõ ràng để tiến gần hơn đến lý tưởng đó.

Đi ngược lại hành vi mong đợi bằng bằng rất có thể sẽ gây rắc rối ở đâu đó, bằng cách nào đó. Và nó không quá khó để sử dụng vật liệu tổng hợp giống như khi bạn thực sự cần chúng mà không ép buộc cốt lõi của bạn sẽ bằng nhau.

Điều đó nói rằng, bạn có thể sử dụng nhiều chức năng tương tác java và macro để làm hỏng hệ thống bằng nếu bạn thực sự muốn. Xem http://clojure.org/datatypes làm điểm xuất phát.

1

Đây là sự điên rồ trong cả Clojure và Java. Không làm điều này. Bạn sẽ phá vỡ hợp đồng của lớp Object và giao diện Map; tất cả mọi thứ sẽ hoàn toàn sụp đổ nếu họ sử dụng lớp bản đồ tùy chỉnh của bạn. Nếu bạn nói rằng hai đối tượng là equal thì mã băm của chúng phải giống hệt nhau, nếu không thì HashMap giữ chúng sẽ không thể đối phó. Bạn có thể làm tất cả mọi thứ băm 0, tất nhiên, nhưng có bản đồ hiệu suất cao của bạn - nó bây giờ là một danh sách liên kết.

Điều đó nói rằng, bạn có thể làm điều gì đó tương tự như vậy trong Clojure hoặc Java bằng cách sử dụng một lần lượt là sorted-map (hoặc SortedMap) với một Công cụ so sánh tùy chỉnh. Tuy nhiên, có vô số những cạm bẫy nếu bạn chọn một Trình so sánh không thực hiện thực sự thực hiện bình đẳng nhưng thay vào đó là một số loại "bình đẳng mờ".

+0

Ghi đè bằng đều miễn là bạn cũng ghi đè hàm băm của mình.Không điên rồ chút nào - tiêu chuẩn, thiết kế thông thường. Bất kỳ chương trình GUI/lint nào tốt sẽ nhắc bạn ghi đè lên một chương trình nếu bạn ghi đè lên chương trình khác. Sử dụng so sánh là một mô hình hơi nastier khi nó xuất khẩu kiến ​​thức từ lớp học của bạn vào lớp khác (so sánh) –

+2

Điều này trông giống như một chút xung đột mô hình. Một số người đang nghĩ rằng "những vật thể tự chứa, hỏi họ xem họ có bình đẳng không" trong khi những người khác đang nghĩ "thành phần của những giá trị bất biến", nơi ý tưởng về đẳng thức là phổ quát. –

+3

Tôi không chống lại trọng số bằng - nó rõ ràng thường cần thiết trong Java. Ghi đè * theo cách anh ta hỏi * là một ý tưởng tồi tệ, vì không thể viết hàm 'hashCode' phù hợp với quyết định có' equals' trả về true cho bất kỳ bản đồ nào chia sẻ ít nhất hai khóa với cái này . – amalloy

5

Để hy vọng thêm một chút rõ ràng cho cuộc thảo luận này, trong Java, việc ghi đè lên hashCodeequals là rất phổ biến. Ví dụ: bạn đang cố gắng theo dõi nhân viên có tên nhưng cũng có thể có biệt hiệu. Mục đích là để đảm bảo rằng những nhân viên đó không bị trùng lặp. Trong trường hợp đó, tôi sẽ ghi đè equalshashCode để chỉ xem ID của nhân viên. Khi những nhân viên đó được nhập vào cấu trúc Tập dữ liệu, họ không bị trùng lặp. Ở Clojure, bạn có thể làm:

(deftype Employee [name id] 
    Object 
    (equals [a b] (= (.id a) (.id b))) 
    (hashCode [this] (.hashCode (.id this))) 
    (toString [this] (.name this))) 

(def vince (Employee. "Vince" 42)) 

(def vincent (Employee. "Vincent" 42)) 

(def tony (Employee. "Tony" 2)) 

(into #{} [vince vincent tony]) 

Nhưng bạn có thể muốn theo đuổi giải pháp cấu trúc dữ liệu "thuần túy" thay vì đi mã băm, bằng đường tương tác Java.

+0

Giải pháp cấu trúc dữ liệu "tinh khiết Clojure" trông như thế nào? –

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