假设我们在Groovy中有一个地图列表,我今天发现了一个奇怪的行为。
List listOfMap = [[1:'b'], [1: 'c']]
println listOfMap[1]
>>> [1: c]
这对我来说很有意义,因为我希望从列表中获得第二个元素。
如果我现在在列表中有从字符串到字符串的映射,那么类似的调用会表现得很奇怪。结构与上面相同,我请求索引' a'。我希望得到一个错误告诉我一个角色作为索引没有意义。
但相反,我得到了一个让我感到困惑的结果:
List listOfMap = [['a':'b'], ['a': 'c']]
println listOfMap['a']
>>> [b, c]
我试图找到相关文档,但无法找到任何内容。
有人可以在使用类似结构时解释不同行为的意图。即,为什么第一个示例不返回[b,c]也至少是一致的,即使在标准索引操作方面可能更令人困惑。
我真的很感谢对行为和推理的解释。
答案 0 :(得分:4)
您的第一个示例会调用Groovy category DefaultGroovyMethods.getAt(List<T> list, int index)
。此方法返回指定索引处的项目。
def listOfMap = [
[1:'b'],
[1: 'c']
]
assert listOfMap[0] == listOfMap.getAt(0)
assert listOfMap[0] == [1:'b']
assert listOfMap[1] == listOfMap.getAt(1)
assert listOfMap[1] == [1: 'c']
这是使用第二个List<Map>
:
def listOfMap = [
['a':'b'],
['a': 'c']
]
assert listOfMap[0] == listOfMap.getAt(0)
assert listOfMap[0] == ['a':'b']
assert listOfMap[1] == listOfMap.getAt(1)
assert listOfMap[1] == ['a': 'c']
您的第二个示例呼叫DefaultGroovyMethods.getAt(Collection collection, String property)
。这种方法......
该方法是用Java编写的,但Groovy的等价物是这样的:
collection.findAll { it.containsKey(property) }.collect { it.get(property) }
您可以通过使用自定义类别拦截它们来见证这些方法:
class GetAtTest {
public static List getAt(Collection self, String property) {
println 'Got ya! Imitating DefaultGroovyMethods.getAt(Collection, String)...'
self.findAll { it.containsKey(property) }.collect { it.get(property) }
}
public static <T> T getAt(List<T> self, int idx) {
println 'Got ya! Imitating DefaultGroovyMethods.getAt(List<T>, int)...'
self.get(idx)
}
}
use(GetAtTest) {
println listOfMap[0]
...
println listOfMap['a']
}
答案 1 :(得分:1)
Emmanuel Rosa的回答非常好。另外,DefaultGroovyMethods.java中public static List getAt(Collection coll, String property)
方法的javadoc解释了这一切。
/**
* Support the subscript operator for Collection.
* <pre class="groovyTestCase">
* assert [String, Long, Integer] == ["a",5L,2]["class"]
* </pre>
*
* @param coll a Collection
* @param property a String
* @return a List
* @since 1.0
*/
public static List getAt(Collection coll, String property) {
//...
}