Was ist der Unterschied zwischen Feldern und Eigenschaften in Julia?

23

Julia hat die Setter - Funktionen setproperty!und setfield!und die Getter - Funktionen getpropertyund getfielddas arbeitet auf structs. Was ist der Unterschied zwischen Eigenschaften und Feldern in Julia?

Zum Beispiel scheint Folgendes darauf hinzudeuten, dass sie dasselbe tun:

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
quelle

Antworten:

27

fieldssind einfach die "Komponenten" einer Struktur. Die Struktur

struct A
   b
   c::Int
end

hat die Felder bund c. Ein Aufruf zum getfieldZurückgeben des an das Feld gebundenen Objekts:

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

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

In früheren Versionen von Julia wurde die Syntax a.bzum "Verringern" verwendet, dh dieselbe wie beim Schreiben getfield(a, :b). Was sich jetzt geändert hat, ist, dass a.bes sich getproperty(a, :b)mit dem Standard-Fallback verringert

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

Standardmäßig hat sich also nichts geändert. Autoren von Strukturen können jedoch überladen getproperty(eine Überladung ist nicht möglich getfield), um der Punktsyntax zusätzliche Funktionen bereitzustellen:

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"

So können wir der Punktsyntax zusätzliche Funktionen hinzufügen (dynamisch, wenn wir möchten). Ein konkretes Beispiel, in dem dies nützlich ist, ist das Paket PyCall.jl, in dem Sie früher schreiben mussten, pyobject[:field] während es jetzt möglich ist, es so zu implementieren, dass Sie schreiben könnenpyobject.field.

Der Unterschied zwischen setfield!und setproperty!ist analog zu dem oben erläuterten Unterschied zwischen getfieldund getproperty.

Darüber hinaus ist es möglich, sich in die Funktion Base.propertynameseinzuhängen, um die Eigenschaften der REPL auf der Registerkarte zu vervollständigen. Standardmäßig werden nur die Feldnamen angezeigt:

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

Durch Überladen können propertynameswir aber auch die zusätzliche Eigenschaft anzeigen lassen q:

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

julia> a.<TAB><TAB>
b c q
Kristoffer Carlsson
quelle
Sie können getfield also nicht überladen?
Alfaizkhan
3
Nein, getfieldist eine spezielle (eingebaute) Funktion. Der Versuch, es zu überladen, gibt den Fehler cannot add methods to a builtin function.
Kristoffer Carlsson
Vielleicht diese Informationen irgendwo zur Antwort hinzufügen?
StefanKarpinski
2
Die Antwort sagt bereits explizit "(es ist nicht möglich zu überladen getfield)", also ist es gewissermaßen schon da.
Kristoffer Carlsson