#groovy #assert
Вопрос:
Отказ от ответственности: Я новичок в Groovy.
Я знаю об этом:
String foo = "foo"
assert foo == "foo" // true
assert "$foo" == "foo" // true
Но сейчас я работаю над приведенным ниже кодом:
String a="a"
Map<String, Object> c = ["$a": [b: 'b']] // [a:[b:b]]
assert c == ["$a":[b:'b']] // true
assert c == ["a":[b:'b']] // false
Caught: Assertion failed:
assert c == ["a":[b:'b']]
| |
| false
[a:['b':'b']]
Assertion failed:
assert c == ["a":[b:'b']]
| |
| false
[a:['b':'b']]
at 1.run(1.groovy:4)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Я заблудился. Почему второе утверждение ложно?
Комментарии:
1. можете ли вы показать полный сбой утверждения с помощью трассировки стека
2. конечно, готово. Спасибо
Ответ №1:
Карты не используют равенство для своего набора ключей, но они используют хэш-код. Поэтому, хотя результат в ваших выходных данных выглядит одинаково (например .toString()
, используется) и выглядит так, как будто он должен работать, на самом деле это невозможно.
def x = "x"
assert x=="$x" // works due to equals
assert x.hashCode() == "$x".hashCode()
// fails:
// Caught: Assertion failed:
//
// assert x.hashCode() == "$x".hashCode()
// | | | | |
// | 120 false| 157
// 'x' 'x'
Поэтому вам придется использовать [("$a".toString()): ...]
здесь довольно многословное
(что предполагает, что вы на самом деле используете здесь не просто значение a
(которое было бы проще записать как [(a): ...]
), а что-то
более сложное).
Эмпирическое правило: всегда используйте неизменяемые данные в качестве ключей для ваших карт.
Ответ №2:
ответ cfrick содержит правильный обходной путь, но основная причина заключается в том, что я невольно сравнивал строку G со строкой:
// String
def a="a" // notice def, to let the compiler decide. NOTE: GString a="a" will fail since Groovy won't cast it
assert a.getClass() == java.lang.String // because that's the default when there are no variables
// GString
def b="$a" // quoted variables create GStrings, not Strings. Here, you could also write Gstring b="$a"
assert b.getClass() == org.codehaus.groovy.runtime.GStringImpl // because of the interpolation
assert "$b".toString().getClass() == java.lang.String // because you converted it
// String
String c="$a"
assert c.getClass() == java.lang.String // because you set the data type to String
// String
def d=(a) // not a, but (a), an expression
assert d.getClass() == java.lang.String // because a is String
assert d.getClass() != org.codehaus.groovy.runtime.GStringImpl
// String
String e="${ -> a }" // with zero arguments, the entire closure result is returned
assert e.getClass() == java.lang.String // lazy evaluation - because you set the data type to String
// Map (verbose)
Map<String, Object> f = [("$b".toString()): [c: 'c']] // to use a var as a key, you need an expression, thus ()
assert f == [("$b".toString()): [c: 'c']] // because you force b from GString to String
assert f != [("$b"): [c: 'c']] // because b is Gstring, not String
// Map (less verbose)
Map<String, Object> g = [ (b.toString()): [c: 'c']] // to use a var as a key, you need an expression, thus ()
assert g == [ (b.toString()): [c: 'c']] // because you force b from GString to String
assert g != [("$b"): [c: 'c']] // because b is Gstring, not String