2012-08-14 23 views
19

Tôi đang cố gắng tạo kiểu dữ liệu/phương thức không thay đổi của riêng mình bằng defrecord trong Clojure. Mục đích là để có một kiểu dữ liệu mà tôi có thể tạo ra các cá thể, và sau đó gọi các phương thức của nó để trả về một bản sao mới của chính nó với các biến bị biến đổi. Nói a và b là vectơ. Tôi muốn cập nhật một giá trị trong cả hai và trả về một bản sao mới của toàn bộ cấu trúc với các vectơ được cập nhật. Điều này rõ ràng không biên dịch, tôi chỉ cố gắng để có được ý tưởng của tôi trên.Từ chối của Clojure - cách sử dụng?

Tôi muốn gọi hàm tạo và sau đó trình biến đổi nhiều lần như tôi muốn (có các chức năng khác không biến đổi, nhưng tôi không muốn làm cho nó phức tạp hơn câu hỏi).

Ngoài ra, nếu đây không phải là Clojure thành ngữ, bạn phải làm như thế nào?

Trả lời

26

Đây là cách bạn xác định hồ sơ của bạn:

(defrecord MyType [a b]) 

Lưu ý rằng trong Clojure bạn không thường xác định "phương pháp" trong vòng loại bản ghi của bản thân (ngoại trừ là nếu bạn muốn thực hiện trực tiếp một giao diện Java hay một giao thức).

Một constructor cơ bản (bắt đầu bằng ->) được tạo ra tự động miễn phí:

(def foo (->MyType [1 2 3] [4 5 6])) 

foo 
=> #user.MyType{:a [1 2 3], :b [4 5 6]} 

Sau đó bạn có thể viết các hàm constructor phức tạp hơn sử dụng này, ví dụ

(defn mytype-with-length [n] 
    (let [a (vec (range n)) 
     b (vec (range n))] 
    (->MyType a b))) 

(mytype-with-length 3) 
=> #user.MyType{:a [0 1 2], :b [0 1 2]} 

Và "đột biến-and-trở lại" cũng đi kèm miễn phí - bạn chỉ có thể sử dụng assoc:

(assoc foo :b [7 8 9]) 
=> user.MyType{:a [1 2 3], :b [7 8 9]} 
+0

Tuyệt vời, cảm ơn. Có một cách dễ dàng/idiomatic để biến đổi cả hai vectơ cùng một lúc, trước khi trở về? –

+2

hoặc assoc-in: '(assoc-in foo [: b 0] 12)' – Kevin

+2

PGS cho phép bạn thực hiện nhiều khóa cùng lúc, ví dụ: '(assoc foo: a [7 8 9]: b [3 4 5])'. Mặc dù thông thường nếu bạn muốn thực hiện bất kỳ đột biến ưa thích/phức tạp nào khác, bạn sẽ muốn kết hợp nó trong một hàm riêng biệt (được đặt tên). – mikera

2

Clojure defrecord dụ:

;; xác định Địa chỉ kỷ lục

(defrecord Address [city state]) 

;; xác định Hồ sơ người

(defrecord Person [firstname lastname ^Address address]) 

;; buid các nhà xây dựng

(defn make-person ([fname lname city state] 
       (->Person fname lname (->Address city state)))) 

;; tạo ra một người

(def person1 (make-person "John" "Doe" "LA" "CA")) 

;; lấy giá trị

(:firstname person1) 
(:city (:address person1)) 
Các vấn đề liên quan