17

所以,让我们有一个字符串列表和一个函数,它接受一个 Hamcrest 匹配器并返回matches()提供的匹配器方法的结果:

public boolean matchIt(final Matcher<? super List<String>> matcher) {
    final List<String> lst = obtainListFromSomewhere();
    return matcher.matches(lst);
}

到目前为止,一切都很好。现在我可以轻松调用:

matchIt(empty());
matchIt(anything());
matchIt(hasItem("item"));
matchIt(everyItem(equalToIgnoringCase("item")));

...因为所有这些工厂静态方法都会生成适合方法签名的匹配器Matcher<? super List<String>>

但是,我相信接受 Iterable 对象的匹配器也应该被该matchIt()方法接受:

matchIt(everyItem(anything()));

所以我天真地改变了matchIt()方法签名:

public boolean matchIt(final Matcher<? super List<? super String>> matcher);

但它根本不起作用。不仅不接受everyItem(anything()),甚至不接受之前正确的everyItem(equalToIgnoringCase("item"))说法(1.7.0_05编译器版本):

actual argument Matcher<Iterable<String>> cannot be converted to Matcher<? super List<? super String>> by method invocation conversion

什么?那么这里有什么问题呢?是matchIt()方法签名还是everyItem()Hamcrest 签名设计错误?还是只是 Java 泛型系统无法修复?非常感谢您的评论!

编辑@rlegendi 我的目的是为客户端提供一个接口,以添加和执行关于列表的谓词。这就是matchIt()方法。在这种情况下调用matchIt(anything())是有意义的,客户端想知道列表是否是任何东西。调用matchIt(empty())意味着客户端想知道列表是否为空。反之亦然。matchIt(everyItem(equalToIgnoringCase("item")))_matchIt(hasItem("item"))

我的目标是尽可能获得最佳 matchIt()方法签名。对于Matcher<? super List<String>>之前的所有场景都可以正常工作。但是,我相信客户端也应该被允许添加Matcher<Iterable<Object>>匹配器(例如matchIt(everyItem(notNullValue()),这里非常有意义,客户端想知道列表中的每个 String 项是否不为空)。

但是我找不到正确的签名,matchIt(Matcher<? super List<? super String>>)不适用于everyItem(notNullValue());

我使用 Hamcrest 1.3。

编辑2:

我相信我已经找到了我的根本误解。

everyItem(anything())表达式返回一个类型为 的对象Matcher<Iterable<Object>>。所以我可以轻松做到Matcher<Iterable<Object>> m = everyItem(anything());

但是我不明白为什么我不能这样做Matcher<? super List<? super String>> m1 = m;。似乎Matcher<Iterable<Object>>不是Matcher<? super List<? super String>>,但我不明白为什么。

我什至做不到Matcher<? super List<?>> m1 = m;Matcher<Iterable<Object>>不是Matcher<? super List<?>>吗?为什么?

4

2 回答 2

4

但是,我相信接受 Iterable 对象的匹配器也应该被 matchIt() 方法接受

不,这是不正确的。而不是Iterable,让我们暂时考虑List一下。所以你有一个Matcher<List<Object>>,它的matches方法需要一个List<Object>。现在,这需要一个List<String>吗?不,您可能已经知道原因——因为它可以将一个类型的对象添加Object到列表中。

现在,我知道在命名类Matcher时,您希望该matches方法是只读的,而不是改变给它的列表。但是,不能保证这一点。如果它确实没有向列表中添加任何内容,则匹配器的正确类型是Matcher<List<?>>,其中 (1) 不允许该matches方法向列表中添加任何内容,除了null,并且 (2) 将允许该matches方法获取随便哪种。

我相信您当前的方法签名public boolean matchIt(final Matcher<? super List<String>> matcher)已经允许Matcher<List<?>>(或Matcher<Iterable<?>>)。

于 2012-10-21T22:02:08.797 回答
1

这有什么问题吗?

public boolean matchIt(final Matcher<? extends Iterable<String>> matcher);
于 2012-10-22T00:06:53.020 回答