2010-07-27 11 views
7

Ben alanlar için tip ipuçlarıyla defrecord kullanarak bir tür yarattı. Ancak, bu tip ipuçlarının kurucularda zorlanmadığını ve onlarla bazı garip şeyler yapabileceğimi fark ettim. Örnek için aşağıdaki pasajı bak:Tip defrecord kurucularınızdaki zorlanmaz ima

user=> (defrecord Person [#^String name #^Integer age]) 
user.Person 
user=> (seq (.getConstructors Person)) 
(#<Constructor public user.Person(java.lang.Object,java.lang.Object, 
java.lang.Object,java.lang.Object)> 
#<Constructor public user.Person(java.lang.Object,java.lang.Object)>) 
user=> (Person. (Integer. 123) "abhinav") 
#:user.Person{:name 123, :age "abhinav"} 

sağlanan tip ipuçlarıyla uyuşmuyor gösterilen yapıcı imzaları (bunlar String ve Integer ikisi için Object kullanın) ve yanlış arazi türleri ile nesneleri oluşturmak mümkün.

benim koduyla yanlış bir şey var mı yoksa Clojure bir hata nedir?

Clojure 1.2.0-beta1'deyim.

+3

kenara, tercih etmelidir '^' # 'dön ^' okuyucu meta tanıştırmak için; #^'nin eski anlamı 1.2'de kullanımdan kaldırılmıştır. –

cevap

8

Tür ipuçları, yansımayı önlemek için kullanılır; Statik olarak işlev veya kurucu args yazmaları için kullanılmazlar (Object altında sınıflandırılamadıkları için ilkel olma istisnası). o ekleyerek protokol uygulanmasına gelince Gibi, onlar basit kayıt için çok fazla bir şey yok, ama onlar olsun yapmak, örneğin:

 
user=> (set! *warn-on-reflection* true) 
true 
user=> (defprotocol P (foo [p])) 
P 
user=> (defrecord R [s] P (foo [_] (.getBytes s))) ; getBytes is a method on String 
Reflection warning, NO_SOURCE_PATH:6 - reference to field getBytes can't be resolved. 
user.R 
user=> (foo (R. 5)) 
java.lang.IllegalArgumentException: No matching field found: getBytes for class java.lang.Integer (NO_SOURCE_FILE:0) 
user=> (defrecord R [^String s] P (foo [_] (.getBytes s))) 
user.R 
user=> (foo (R. 5)) 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String (NO_SOURCE_FILE:0) 

iki sürüm arasındaki fark, ikincisinin baytkodu String.getBytecode() arayarak yayar olmasıdır (Bu nedenle, bir tamsayı geçtiğinde ClassCastException), eskide tam olarak .getBytes tam olarak neye bakması gerektiği, işleve geçen çalışma zamanı nesnesine göre anlamlıdır (ve bu işlem bir Tamsayı geçtiğinde başarısız olur). kodunuzu zaten 1.2 özelliklere bağlıdır eğer bir As

5

Bildiğim kadarıyla söyleyebilirim, basit bir tür söz konusu olduğunda deftype ve defprotocol alanlarda tipi ipuçları şu anda sadece uygulanır:

(deftype Foo [^int x]) 

(Foo. 5) ; => OK 
(Foo. :foo) ; => no go 

;; ... and likewise with defprotocol 

Gerçi bu tanınmış bir konu olmanın çok hayal meyal hatırlıyorum Planın bu davranışı belgelemek mi yoksa ilkel olmayan ipuçlarını uygulamak mı olduğuna emin değilim. Bunu öğrenmeye çalışacağım.