有人在问这个问题。我们一步步来解决。
下面先给出一个不能继承的class。
其用法如下:
@class S begin
a :: Int
f(self, arg::Int) = self.a + arg
end
s = S(1)
s.f(2)
# => 3
实现如下:
class.jl
function div_set(method ::Expr)
if method.head == :(::)
:field
else
:method
end
end
function div_set(method::Symbol)
:field
end
function div_set(method::LineNumberNode)
nothing
end
function group_by(f, seq)
groups = Dict{Any, Any}()
foreach(seq) do elem
mapped = f(elem)
get(groups, mapped) do
groups[mapped] = []
end |>
function (group)
push!(group, elem)
end
end
groups
end
macro class(class_name, methods)
groups = group_by(div_set, methods.args)
get(groups, :field) do
[]
end |>
function(group)
expr =
quote
struct $class_name
$(group...)
end
end
@eval __module__ $expr
end
cls = @eval __module__ $class_name
get(groups, :method) do
[]
end |>
function(group)
map(group) do method
method_name = method.args[1].args[1]
this = method.args[1].args[2]
deleteat!(method.args[1].args, [1, 2])
method.args[1].head = :tuple
if method.head === :(=)
method.head = :(->)
end
bound_fn =
quote
($this :: $cls) -> begin
$method
end
end
method_name => @eval __module__ $bound_fn
end |>
function (seq)
dispatcher = Dict(seq)
m_this = Symbol(".", "this")
m_attr = Symbol(".", "attr")
fields = fieldnames(cls)
property = quote
function Base.getproperty($m_this :: $cls, $m_attr :: $Symbol)
if $m_attr in $fields
getfield($m_this, $m_attr)
else
$dispatcher[$m_attr]($m_this)
end
end
end
property |> esc
end
end
end
以上实现有一些不足,例如method和field的覆盖问题(以上实现默认了field优先),例如self不能标注类型,没有实现静态方法等。当然要处理它们也是简单的, 如果你需要频繁使用class,那就解决这些问题即可。
关于继承的实现有多种方法,例如python的mro。
在车上写码打字都很痛苦,后面再更。