5 julia
假设我有以下内容Employee struct:
mutable struct Employee
_id::Int64
_first_name::String
_last_name::String
function Employee(_id::Int64,_first_name::String,_last_name::String)
# validation left out.
new(_id,_first_name,_last_name)
end
end
Run Code Online (Sandbox Code Playgroud)
如果我想实现我自己的,setproperty!()我可以这样做:
function setproperty!(value::Employee,name::Symbol,x)
if name == :_id
if !isa(x,Int64)
throw(ErrorException("ID type is invalid"))
end
setfield!(value,:_id,x)
end
if name == :_first_name
if is_white_space(x)
throw(ErrorException("First Name cannot be blank!"))
end
setfield!(value,:_first_name,x)
end
if name == :_last_name
if is_white_space(x)
throw(ErrorException("Last Name cannot be blank!"))
end
setfield!(value,:_last_name,x)
end
end
Run Code Online (Sandbox Code Playgroud)
我执行setproperty!()正确了吗?
setfield!()我使用for_first_name和,的原因_last_name是因为如果我这样做:
if name == :_first_name
setproperty!(value,:_first_name,x) # or value._first_name = x
end
Run Code Online (Sandbox Code Playgroud)
它会导致 aStackOverflowError因为它递归地使用setproperty!().
我真的不喜欢使用setproperty!(),因为随着参数数量的增加, 也会增加setproperty!()。
它还让人想起使用Enum 和 if 语句(只有我们用 切换Enum)Symbol。
我喜欢的一种解决方法是记录字段的含义private并使用提供的setter来设置字段:
function set_first_name(obj::Employee,first_name::AbstractString)
# Validate first_name before assigning it.
obj._first_name = first_name
end
Run Code Online (Sandbox Code Playgroud)
该函数较小且用途单一。
当然,这并不能阻止某人使用setproperty!(),setfield!()或value._field_name = x,但如果您要规避提供的内容setter,那么您将需要承担这样做的后果。
当然,这并不能阻止某人使用 setproperty!()、setfield!() 或 value._field_name = x,但如果您要规避提供的 setter,那么您将需要承担这样做的后果。
我建议您这样做,定义 getter、setter 函数,而不是重载getproperty/setproperty!. 在野外,我看到的重载的主要用途getproperty/setproperty!是可以根据数据计算字段。对于 getter/setter 模式,我建议您使用约定!: getter:
function first_name(value::Employee)
return value._first_name
end
Run Code Online (Sandbox Code Playgroud)
设置者:
function first_name!(value::Employee,text::String)
#validate here
value._first_name = text
return value._first_name
end
Run Code Online (Sandbox Code Playgroud)
如果您的结构是可变的,则可能某些字段未初始化。您可以通过添加一个方法来添加默认的 getter:
function first_name(value::Employee,default::String)
value_stored = value._first_name
if is_initialized(value_stored) #define is_initialized function
return value_stored
else
return default
end
end
Run Code Online (Sandbox Code Playgroud)
使用默认的 setter/getter 时,first_name(val,text)和之间的唯一区别first_name!(val,text)是 的可变性val,但结果是相同的。如果您正在执行可变函数与不可变函数,则很有用。正如你所说,getproperty/setproperty!相比之下,这很麻烦。如果您想禁止访问这些字段,您可以这样做:
Base.getproperty(val::Employee,key::Symbol) = throw(error("use the getter functions instead!")
Base.setproperty!(val::Employee,key::Symbol,x) = throw(error("use the setter functions instead!")
Run Code Online (Sandbox Code Playgroud)
val.key禁止使用and的语法糖val.key = x。(如果有人真的想要原始访问,仍然有getfield/setfield!,但他们被警告了。)
最后,我在 julia 文档中找到了这个建议,建议使用 getter/setter 方法而不是直接字段访问 https://docs.julialang.org/en/v1/manual/style-guide/#Prefer-exported-methods-over-直接现场访问
| 归档时间: |
|
| 查看次数: |
333 次 |
| 最近记录: |