В чем разница между полями и свойствами в Юлии? - PullRequest
22 голосов
/ 01 октября 2019

Джулия имеет функции установки setproperty! и setfield! и функции получения getproperty и getfield, которые работают с конструкциями. В чем разница между свойствами и полями в Julia?

Например, следующее указывает на то, что они делают одно и то же:

julia> mutable struct S
           a
       end

julia> s = S(2)
S(2)

julia> getfield(s, :a)
2

julia> getproperty(s, :a)
2

julia> setfield!(s, :a, 3)
3

julia> s
S(3)

julia> setproperty!(s, :a, 4)
4

julia> s
S(4)

1 Ответ

26 голосов
/ 01 октября 2019

fields - это просто «компоненты» структуры. Структура

struct A
   b
   c::Int
end

имеет поля b и c. Вызов getfield возвращает объект, связанный с полем:

julia> a = A("foo", 3)
A("foo", 3)

julia> getfield(a, :b)
"foo"

В ранних версиях Julia синтаксис a.b использовался для «понижения», то есть совпадения с написанием getfield(a, :b). Что изменилось сейчас, так это то, что a.b понижается до getproperty(a, :b) со стандартным отступлением

getproperty(a::Type, v::Symbol) = getfield(a, v)

Так что по умолчанию ничего не изменилось. Однако авторы структур могут перегрузить getproperty (перегрузить getfield невозможно), чтобы обеспечить дополнительную функциональность для синтаксиса точек:

julia> function Base.getproperty(a::A, v::Symbol)
           if v == :c
               return getfield(a, :c) * 2
           elseif v == :q
               return "q"
           else
               return getfield(a, v)
           end
       end

julia> a.q
"q"

julia> getfield(a, :q)
ERROR: type A has no field q

julia> a.c
6

julia> getfield(a, :c)
3

julia> a.b
"foo"

Таким образом, мы можем добавить дополнительные функции в синтаксис точки. (динамически, если мы хотим). В качестве конкретного примера, где это полезно, можно привести пакет PyCall.jl, в котором вы должны были писать pyobject[:field], а теперь можно реализовать его так, что вы можете написать pyobject.field.

Разница междуsetfield! и setproperty! аналогичны разнице между getfield и getproperty, описанной выше.

Кроме того, можно подключиться к функции Base.propertynames, чтобы обеспечить завершение свойств табуляциив REPL. По умолчанию будут отображаться только имена полей:

julia> a.<TAB><TAB>
b c

Но, перегрузив propertynames, мы можем заставить его также показать дополнительное свойство q:

julia> Base.propertynames(::A) = (:b, :c, :q)

julia> a.<TAB><TAB>
b c q
...