Jaka jest różnica między polami i właściwościami w Julii?

23

Julia ma funkcje ustawiające setproperty!i setfield!oraz funkcje getter getpropertyi getfieldktóre działają na elemencie. Jaka jest różnica między właściwościami a polami w Julii?

Na przykład następujące wydaje się wskazywać, że robią to samo:

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)
Kristoffer Carlsson
źródło

Odpowiedzi:

27

fieldssą po prostu „komponentami” struktury. Struktura

struct A
   b
   c::Int
end

ma pola bi c. Wywołanie getfieldzwracające obiekt związany z polem:

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

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

We wczesnych wersjach Julii składnia a.bużywana była do „obniżania”, tj. Bycia takim samym jak pisanie getfield(a, :b). To, co się teraz zmieniło, to a.bobniżenie do getproperty(a, :b)domyślnego stanu rezerwowego

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

Domyślnie nic się nie zmieniło. Jednak autorzy struktur mogą przeciążać getproperty(nie można przeciążać getfield), aby zapewnić dodatkową funkcjonalność składni kropek:

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"

Możemy więc dodać dodatkową funkcjonalność do składni kropek (dynamicznie, jeśli chcemy). Konkretnym przykładem, w którym jest to przydatne, jest pakiet PyCall.jl, w którym kiedyś musiałeś pisać pyobject[:field] , ale teraz możesz go zaimplementować tak, abyś mógł pisaćpyobject.field.

Różnica między setfield!i setproperty!jest analogiczna do różnicy między getfieldi getproperty, wyjaśnionej powyżej.

Ponadto możliwe jest podpięcie się do funkcji w Base.propertynamescelu zapewnienia uzupełnienia tabulacji właściwościami w REPL. Domyślnie wyświetlane są tylko nazwy pól:

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

Ale przez przeciążenie propertynamesmożemy sprawić, że pokaże także dodatkową właściwość q:

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

julia> a.<TAB><TAB>
b c q
Kristoffer Carlsson
źródło
Więc nie możesz przeciążać getfielda?
Alfaizkhan
3
Nie, getfieldjest specjalną (wbudowaną) funkcją. Próba przeciążenia spowoduje błąd cannot add methods to a builtin function.
Kristoffer Carlsson
Może gdzieś dodać tę informację do odpowiedzi?
StefanKarpinski
2
Odpowiedź już wyraźnie mówi „(przeciążenie nie jest możliwe getfield)”, więc w pewnym sensie już tam jest.
Kristoffer Carlsson