В чем разница между полями и свойствами в Юлии?

23

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

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

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)
Кристоффер Карлссон
источник

Ответы:

27

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
Кристоффер Карлссон
источник
Таким образом, вы не можете перегрузить getfield?
Альфаизхан
3
Нет, getfieldэто специальная (встроенная) функция. Попытка перегрузить это даст ошибку cannot add methods to a builtin function.
Кристоффер Карлссон
Может быть, добавить эту информацию к ответу где-нибудь?
Стефан Карпински
2
Ответ уже явно говорит "(невозможно перегрузить getfield)", так что, в некотором смысле, он уже есть.
Кристоффер Карлссон