#inheritance #module #julia
Вопрос:
Как я могу предоставить реализацию метода по умолчанию в Julia в отдельном модуле? Если абстрактный тип живет в том же модуле, у меня нет проблем, например, это работает так, как я ожидаю:
abstract type Foo end
howdy(x::Foo)::Union{String, Nothing} = nothing
struct Bar <: Foo end
function howdy(x::Bar)::Union{String, Nothing}
"I'm a Bar!"
end
struct Baz <: Foo end
if abspath(PROGRAM_FILE) == @__FILE__
bar = Bar()
s = howdy(bar)
if isa(s, String)
println(s)
end
baz = Baz()
t = howdy(baz)
if isa(t, String)
println(t)
end
end
Однако, как только я помещаю абстрактный тип в его собственный модуль, он больше не работает:
В src/qux.jl
, я вставил:
module qux
abstract type Foo end
howdy(x::Foo)::Union{String, Nothing} = nothing
export Foo, howdy
end # module
а потом reproduce.jl
я вставил:
using qux
struct Bar <: Foo end
function howdy(x::Bar)::Union{String, Nothing}
"I'm a Bar!"
end
struct Baz <: Foo end
if abspath(PROGRAM_FILE) == @__FILE__
bar = Bar()
s = howdy(bar)
if isa(s, String)
println(s)
end
baz = Baz()
t = howdy(baz)
if isa(t, String)
println(t)
end
end
Тогда я получаю:
julia --project=. reproduce.jl
I'm a Bar!
ERROR: LoadError: MethodError: no method matching howdy(::Baz)
Closest candidates are:
howdy(::Bar) at ~/qux/reproduce.jl:5
Stacktrace:
[1] top-level scope
@ ~/qux/reproduce.jl:18
in expression starting at ~/qux/reproduce.jl:11
Ответ №1:
Ваша проблема описана здесь, в руководстве Julia.
Проблема в том, что в вашем коде, как вы можете видеть здесь:
julia> module qux
abstract type Foo end
howdy(x::Foo)::Union{String, Nothing} = nothing
export Foo, howdy
end # module
Main.qux
julia> using .qux
julia> struct Bar <: Foo end
julia> function howdy(x::Bar)::Union{String, Nothing}
"I'm a Bar!"
end
howdy (generic function with 1 method)
julia> methods(howdy)
# 1 method for generic function "howdy":
[1] howdy(x::Bar) in Main at REPL[4]:1
julia> methods(qux.howdy)
# 1 method for generic function "howdy":
[1] howdy(x::Foo) in Main.qux at REPL[1]:5
У вас есть две различные howdy
функции, каждая из которых имеет один метод. Один определен в qux
модуле, а другой-в Main
модуле.
Что вы хотите сделать, так это добавить метод к howdy
функции, определенной в qux
модуле. Обычно я бы сделал это, указав имя экспортируемой функции с именем модуля, так как это четкий способ указать, что вы хотите сделать:
julia> module qux
abstract type Foo end
howdy(x::Foo)::Union{String, Nothing} = nothing
export Foo, howdy
end # module
Main.qux
julia> using .qux
julia> struct Bar <: Foo end
julia> function qux.howdy(x::Bar)::Union{String, Nothing}
"I'm a Bar!"
end
julia> methods(qux)
# 0 methods:
julia> methods(howdy)
# 2 methods for generic function "howdy":
[1] howdy(x::Bar) in Main at REPL[4]:1
[2] howdy(x::Foo) in Main.qux at REPL[1]:5
как вы можете видеть теперь, у вас есть одна howdy
функция, имеющая два метода, и все они будут работать так, как вы хотите.