Groovy มีพฤติกรรมแปลกๆ ดูสองตัวอย่างด้านล่าง:
def list = [[BigDecimal.ONE]]
list.each {
println it.class
}
พิมพ์:
คลาส java.util.ArrayList
และ
def list = [[BigDecimal.ONE]]
list.each { BigDecimal it ->
println it.class
}
พิมพ์:
คลาส java.math.BigDecimal
ความแตกต่างเพียงอย่างเดียวในตัวอย่างคืออันที่ 2 มีประเภทอาร์กิวเมนต์สำหรับการปิดที่ระบุ แต่นี่ไม่ได้อธิบายว่าทำไมและอย่างไร List
ภายในจึงถูกแปลงเป็น BigDecimal
ฉันคาดหวังไว้ดีกว่า ClassCastException
นอกจากนี้พฤติกรรมนี้ไม่สอดคล้องกัน ราวกับว่ามีองค์ประกอบเพิ่มเติมในรายการภายในก็จะล้มเหลวด้วย MissingMethodException
เราพบว่าการแปลงประเภทเวทย์มนตร์นี้เกิดขึ้นใน ClosureMetaClass
(บรรทัด: 256)
มันเป็นพฤติกรรมที่ออกแบบมาหรือเป็นข้อบกพร่อง?
แก้ไข: ฉันพบปัญหาข้างต้นขณะพยายามขัดขวางวิธีการด้วย Spock วิธีการรับ Collection
เป็นพารามิเตอร์ ลองพิจารณาอีกตัวอย่างหนึ่ง:
def 'stub a method with collection as argument'() {
given:
def input = [1, 2, 3]
def capturedArgument
List listStub = Stub()
listStub.addAll(input) >> {
capturedArgument = it
}
when:
listStub.addAll(input)
then:
input.class == capturedArgument.class
}
มันล้มเหลวด้วย:
Condition not satisfied:
input.class == capturedArgument.class
| | | | |
| | | [[1, 2, 3]] class java.util.Arrays$ArrayList
| | false
| class java.util.ArrayList
[1, 2, 3]
ปัญหาคืออาร์กิวเมนต์ it
มาเป็น List
ฝังอยู่ในอีก List
ลงในการปิดเมธอด stubbing อะไรนะ?
วิธีเดียวที่จะเอาชนะสิ่งนี้ได้คือวิธีการขัดจังหวะด้วย ประเภทอาร์กิวเมนต์ที่เหมือนกันทุกประการกับประเภทอินพุต เช่น
listStub.addAll(input) >> { ArrayList it ->
...จากนั้นก็สอบผ่าน เป็นไปไม่ได้เลยเพราะฉันต้องใช้อินเทอร์เฟซเป็นประเภทอาร์กิวเมนต์ stub ไม่ใช่การใช้งานเฉพาะ และเมื่อมีการประกาศเช่นนั้น
listStub.addAll(input) >> { List it ->
or
listStub.addAll(input) >> { Collection it ->
...มันล้มเหลวในลักษณะเดียวกับที่ไม่มีประเภทเพราะรายการ input ถูกฝังอยู่ในรายการอื่น
นี่คือตัวอย่างสด หากคุณต้องการวิ่งและเล่นกับมัน
java.util.Arrays$ArrayList
เนื่องจากโค้ดส่วนนี้ในDefaultGroovyMethods.java
:public static <T> boolean addAll(Collection<T> self, T[] items) { return self.addAll(Arrays.asList(items)); }
มันทำงานถูกต้องทั้งหมด หากคุณระบุอาร์กิวเมนต์อย่างชัดเจน อาร์กิวเมนต์นั้นจะถูกแปลงโดยอัตโนมัติและจะไม่มีข้อยกเว้นเกิดขึ้น ดู: github com/groovy/groovy-core/blob/master/src/main/org/codehaus/ - person Opal   schedule 05.01.2015it
หรือพารามิเตอร์การปิดที่ไม่ได้พิมพ์เพียงรายการเดียวจะมีรายการอาร์กิวเมนต์ของเมธอด หากใช้พารามิเตอร์การปิดที่พิมพ์แทน Spock จะพยายามทำลายโครงสร้างตามความหมายของ Groovy ดูที่ docs.spockframework.org - person Peter Niederwieser   schedule 05.01.2015List
ซึ่งแสดงถึงอาร์กิวเมนต์ของการร้องขอที่ถูกตัดทอน list.) กล่าวอีกนัยหนึ่ง เมื่อทำการสแตกเมธอดด้วยพารามิเตอร์ประเภทเดียวIterable
,Collection
หรือList
คุณจะต้องทำลายโครงสร้างด้วยตนเอง (>> { args -> args[0] }
หรือ>> { it[0] }
) - person Peter Niederwieser   schedule 06.01.2015