Проверяет ли `==` для структуры рекурсивно в Julia? Кажется, нет

#struct #julia

#структура #джулия

Вопрос:

Существует поведение, которое я не понимаю при проверке равенства в Julia в отношении объектов «struct». В документации указано :: «Для коллекций == обычно вызывается рекурсивно для всего содержимого, хотя другие свойства (например, форма для массивов) также могут быть приняты во внимание«. Хотя кажется, что для структур оно приведено === или что-то в этом роде. Вот минимальный рабочий пример :

Как и ожидалось :

 string1 = String("S")
string2 = String("S")
string1 == string2 
  

=> возвращает true

и :

 set1 = Set(["S"])
set2 = Set(["S"])
set1 == set2
  

=> возвращает true


НО! И это то, чего я не понимаю :

 struct StringStruct
    f::String
end
stringstruct1 = StringStruct("S")  
stringstruct2 = StringStruct("S")  
stringstruct1 == stringstruct2  
  

=> возвращает true

Однако :

 struct SetStruct  
    f::Set{String}  
end
setstruct1 = SetStruct(Set(["S"]))
setstruct2 = SetStruct(Set(["S"]))
setstruct1 == setstruct2 
  

=> возвращает false


Для меня это выглядит так, как будто === проверяется на элементах структуры.

Итак, мой вопрос: каково реальное поведение == при тестировании на структурах? Приводит ли это == или === ? В случае, если он выдает == , как указано в документации, в чем смысл, который я неправильно понимаю?

Комментарии:

1. Дополнительная информация: существует проблема, связанная с рекурсивным сравнением структур, как вы упомянули ( github.com/JuliaLang/julia/issues/4648 ). Однако этого не будет ни в одной версии Julia 1.X, так что это будет, по крайней мере, Julia 2.0, прежде чем автоматическая рекурсивная проверка станет частью языка (если это вообще произойдет).

Ответ №1:

Для struct s по умолчанию == возвращается к === , так что, например:

 setstruct1 == setstruct2
  

это то же самое, что

 setstruct1 === setstruct2
  

Итак, теперь мы переходим к тому, как === это работает. И это определяется как:

Определите x , идентичны ли y и в том смысле, что ни одна программа не может их различить.

(Я опускаю остальную часть определения, поскольку считаю, что это первое предложение создает хорошую ментальную модель).

Теперь ясно stringstruct1 и stringstruct2 не различимо. Они неизменяемы и содержат строки, которые неизменны в Julia. В частности, они имеют одинаковое hash значение (что не является окончательным тестом, но является хорошей ментальной моделью здесь).

 julia> hash(stringstruct1), hash(stringstruct2)
(0x9e0bef39ad32ce56, 0x9e0bef39ad32ce56)
  

Теперь setstrict1 и setstruct2 различимы. Они хранят разные наборы, хотя на момент сравнения эти наборы содержат одни и те же элементы, но у них разные ячейки памяти (поэтому в будущем они могут быть разными — короче говоря, они различимы). Обратите внимание, что эти структуры, в частности, имеют разные хэши:

 julia> hash(setstruct1), hash(setstruct2)
(0xe7d0f90913646f29, 0x3b31ce0af9245c64)
  

Теперь обратите внимание на следующее:

 julia> s = Set(["S"])
Set{String} with 1 element:
  "S"

julia> ss1 = SetStruct(s)
SetStruct(Set(["S"]))

julia> ss2 = SetStruct(s)
SetStruct(Set(["S"]))

julia> ss1 == ss2
true

julia> ss1 === ss2
true

julia> hash(ss1), hash(ss2)
(0x9127f7b72f753361, 0x9127f7b72f753361)
  

На этот раз ss1 и ss2 проходят все тесты, так как они снова неразличимы (если вы измените ss1 , то ss2 изменения будут синхронизированы, поскольку они остаются неизменными Set ).

Комментарии:

1. Отлично! Это полезно, полно и понятно. Спасибо!

Ответ №2:

Хотя ответ Богумила объясняет, что происходит, позвольте мне показать, как привести поведение, которое вы ожидаете, к вашему коду.

Просто добавьте следующие строки.

 abstract type Comparable end
import Base.==
==(a::T, b::T) where T <: Comparable =
    getfield.(Ref(a),fieldnames(T)) == getfield.(Ref(b),fieldnames(T))
  

Теперь вы можете сделать свою структуру сопоставимой по своему усмотрению:

 struct SetStruct <: Comparable 
    f::Set{String}  
end

setstruct1 = SetStruct(Set(["S"]))
setstruct2 = SetStruct(Set(["S"]))
  

Тесинг:

 julia> setstruct1  == setstruct2
true
  

Комментарии:

1. Отлично! Это полезно для простого сравнения структур. Спасибо.