Apa perbedaan antara bidang dan properti di Julia?

23

Julia memiliki fungsi setter setproperty!dan setfield!fungsi pengambil getpropertydan getfieldyang beroperasi pada struct. Apa perbedaan antara properti dan bidang di Julia?

Misalnya, yang berikut ini nampaknya mengindikasikan bahwa mereka melakukan hal yang sama:

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
sumber

Jawaban:

27

fieldshanyalah "komponen" dari sebuah struct. Struct

struct A
   b
   c::Int
end

memiliki bidang bdan c. Panggilan untuk getfieldmengembalikan objek yang terikat ke bidang:

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

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

Dalam versi awal Julia, sintaksinya a.bdigunakan untuk "lebih rendah", yaitu sama dengan, menulis getfield(a, :b). Apa yang telah berubah sekarang adalah semakin a.brendah getproperty(a, :b)dengan fallback default

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

Jadi secara default, tidak ada yang berubah. Namun, penulis struct dapat membebani berlebihan getproperty(tidak mungkin membebani berlebihan getfield) untuk menyediakan fungsionalitas tambahan untuk sintaks dot:

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"

Jadi kita dapat menambahkan fungsionalitas tambahan ke sintaks dot (secara dinamis jika kita mau). Sebagai contoh konkret di mana ini berguna adalah untuk paket PyCall.jl di mana Anda dulu harus menulis pyobject[:field] sementara mungkin sekarang untuk mengimplementasikannya sehingga Anda dapat menulispyobject.field.

Perbedaan antara setfield!dan setproperty!analog dengan perbedaan antara getfielddan getproperty, dijelaskan di atas.

Selain itu, dimungkinkan untuk menghubungkan ke fungsi Base.propertynamesuntuk menyediakan penyelesaian tab properti di REPL. Secara default, hanya nama bidang yang akan ditampilkan:

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

Tetapi dengan kelebihan beban propertynameskita dapat membuatnya juga menunjukkan properti tambahan q:

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

julia> a.<TAB><TAB>
b c q
Kristoffer Carlsson
sumber
Jadi Anda tidak bisa membebani getfield?
Alfaizkhan
3
Tidak, getfieldadalah fungsi khusus (bawaan). Mencoba membebani itu akan memberikan kesalahan cannot add methods to a builtin function.
Kristoffer Carlsson
Mungkin menambahkan info itu ke jawaban di suatu tempat?
StefanKarpinski
2
Jawabannya sudah secara eksplisit mengatakan "(tidak mungkin untuk membebani getfield)" jadi, dalam arti, sudah ada di sana.
Kristoffer Carlsson