在 Julia 中定义抽象类型的默认方法

use*_*717 6 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
Run Code Online (Sandbox Code Playgroud)

但是,一旦我将抽象类型放入其自己的模块中,它就不再起作用:

在 中src/qux.jl,我输入:

module qux

abstract type Foo end

howdy(x::Foo)::Union{String, Nothing} = nothing

export Foo, howdy
end # module
Run Code Online (Sandbox Code Playgroud)

然后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
Run Code Online (Sandbox Code Playgroud)

然后我得到:

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
Run Code Online (Sandbox Code Playgroud)

Bog*_*ski 6

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
Run Code Online (Sandbox Code Playgroud)

您有两个不同的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
Run Code Online (Sandbox Code Playgroud)

正如您现在所看到的,您有一个howdy具有两个方法的函数,并且所有函数都将按您想要的方式工作。