2012-03-01 143 views
9

我試圖調試一些使用mixin的代碼,我能夠將我的問題簡化爲這個例子。我有一個父類,它通過一個mixin和一個從父類繼承的子類來接收方法。如果我嘗試替換子類的實例上的方法,它將起作用除非我更換的方法在父類的實例被替換之前調用。如果已被稱爲然後,我不能沒有它Groovy在這裏做什麼?

所以這個代碼:

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A {} 

def b = new B() 
def a = new A() 
a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

將產生:

但如果你註釋掉第13行(帶有評論的評論),你會得到:

獲獎

爲什麼會出現這種情況?我期望在Groovy的元類模型的背景下有一些合理的方法,但我不明白。

這是Groovy的1.8.6

+1

我也可以在Groovy 1.8.4中重現這一點。聞起來像一個臭蟲給我;但我並不太在意Groovy元編程,所以我不知道。 – epidemian 2012-03-01 22:55:08

+0

感謝您的注意事項,如果我最終提出了一個錯誤,我一定會加入。 – mfollett 2012-03-01 23:27:00

+0

我在groovy用戶郵件列表上問這個,聞起來像是一個bug ... – 2012-03-01 23:47:35

回答

3

元類上的方法調用,並混入有自己的處理程序時看。 兩者都是延遲加載的,而靜態的,如果你不調用一個方法,靜態延遲加載不會發生。
Mixins優先於metaClass覆蓋,這就是爲什麼它顯示foo並且如果初始化A而不會獲勝。
meta定義在它所應用的對象上,以便按需要解析它。Object.class .metaClass(即這裏B.metaClass)。 有趣的是這產生了:

groovy.lang.MissingMethodException: No signature of method: B.foo() is applicable for argument types:() values: [] 
Possible solutions: foo(), foo(java.lang.Object), bar(), any(), use([Ljava.lang.Object;), find(groovy.lang.Closure) 

第B定義FOO解決錯誤:

class B extends A { 
    def foo() { println 'not winning' } 
} 

你的答案是的Mixin影響類metastore,和類方法優先對象metastore方法。

證明:

@Mixin(M) 
class B extends A { 

} 

a.bar() //<-- comment out this line and see the difference 
B.metaClass.foo = {println 'class winning'} 
b.metaClass.foo = {println 'object winning'} 
b.bar() 

產量:

foo 
class winning 

一種不同的方法

class M { 
    protected foo() { println 'foo' } 
} 

@Mixin(M) class A { 
def bar() { foo() } 
} 

class B extends A { 
    def bar() { foo() } 
} 

class C extends B { 
    def foo() { println 'wat' } 
} 

@Mixin(M) 
class D extends C { } 

def b = new B() 
def a = new A() 
def c = new C() 
def d = new D() 


a.bar() //<-- comment out this line and see the difference 
b.metaClass.foo = {println 'winning'} 
b.bar() 

c.metaClass.foo = {println 'losing'} 
c.bar() 

d.metaClass.foo = {println 'draw'} 
d.bar() 

息率

foo 
winning 
wat 
wat 
+0

你有來源可以引用此信息嗎?我不完全按照你的回答,也找不到有關Groovy的metastore的信息。 – mfollett 2012-04-03 22:43:05

+0

所有這一切都來自文檔,並自己控制檯。在我看來,你的問題非常有趣,值得一讀博客文章。文檔的Dynamic Groovy頁面已經提供了一些答案http://groovy.codehaus.org/Per-Instance+MetaClass – Gepsens 2012-04-08 09:33:12