我有一个我在这里写的模块:
# Hello.jl
module Hello
function foo
return 1
end
end
和
# Main.jl
using Hello
foo()
当我运行Main
模块时:
$ julia ./Main.jl
我收到此错误:
ERROR: LoadError: ArgumentError: Hello not found in path
in require at ./loading.jl:249
in include at ./boot.jl:261
in include_from_node1 at ./loading.jl:320
in process_options at ./client.jl:280
in _start at ./client.jl:378
while loading /Main.jl, in expression starting on line 1
答案 0 :(得分:26)
自Julia v0.7和v1.0发行以来,此问题有了一个新的答案,该答案略有不同。我只需要这样做,就可以将发现的信息发布在这里。
正如其他解决方案中已经解释的那样,有必要包括定义模块的相关脚本。但是,由于自定义模块不是软件包,因此无法像以前的Julia版本一样使用相同的using
或import
命令将其作为软件包加载。
因此,Main.jl脚本将使用这样的相对导入来编写:
include("./Hello.jl")
using .Hello
foo()
我发现在Stefan Karpinski's discourse comment中对此问题做了简单解释。正如他所描述的,在处理子模块时,情况也会变得更加复杂。 documentation section on module paths也是很好的参考。
答案 1 :(得分:15)
已经有一些简短的答案,但我希望尽可能提供更完整的答案。
当您运行using MyModule
时,Julia只会在名为LOAD_PATH
的目录列表中搜索它。如果您在Julia REPL中键入LOAD_PATH
,您将获得以下内容:
2-element Array{ByteString,1}:
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
这些是Julia将在您键入using Hello
时搜索要包含的模块的目录。在您提供的示例中,由于Hello
中没有LOAD_PATH
,因此Julia无法找到它。
如果要包含本地模块,可以指定其相对于当前工作目录的位置。
julia> include("./src/Hello.jl")
一旦包含文件,您就可以正常运行using Hello
以获得所有相同的行为。对于一个关闭脚本,这可能是最好的解决方案。但是,如果您发现自己经常需要include()
某组目录,则可以将其永久添加到LOAD_PATH
。
将目录添加到LOAD_PATH
如果您希望定期使用存储在Julia LOAD_PATH
之外的特定模块,则手动将目录添加到LOAD_PATH
可能会很麻烦。在这种情况下,您可以将其他目录附加到LOAD_PATH
环境变量。无论何时发出import
或using
命令,Julia都会自动搜索这些目录。
执行此操作的一种方法是将以下内容添加到.basrc
,.profile
,.zshrc
。
export JULIA_LOAD_PATH="/path/to/module/storage/folder"
这会将该目录附加到Julia将搜索的标准目录中。如果你然后运行
julia> LOAD_PATH
它应该返回
3-element Array{ByteString,1}:
"/path/to/module/storage/folder"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
您现在可以自由运行using Hello
,Julia会自动找到该模块(只要它存储在/path/to/module/storage/folder
下面。
有关详细信息,请查看Julia Docs中的this页面。
答案 2 :(得分:11)
您应include("./Hello.jl")
之前using Hello
答案 3 :(得分:9)
虽然张实唯的答案是最方便的,你不应该在REPL之外使用include
。如果您正在编写程序文件,请务必将相应的目录添加到LOAD_PATH。雷米给出了如何做的非常好的解释,但它也值得解释为什么你应该首先这样做。 (另外来自文档:push!(LOAD_PATH, "/Path/To/My/Module/")
,但请注意您的模块和文件必须具有相同的名称)
问题在于,include
的所有内容都会定义在您调用include
的位置,即使它也在其他地方定义。由于模块的目标是重复使用,您最终可能会在多个文件中使用MyModule
。如果你在每个文件中调用include
,那么每个文件都有自己的MyModule定义,即使它们是相同的,也会有不同的定义。这意味着MyModule
中定义的任何数据(例如数据类型)都不会相同。
要了解这是一个巨大的问题,请考虑以下三个文件:
types.jl
module TypeModule
struct A end
export A
end
a_function.jl
include("types.jl")
module AFunctionModule
using TypeModule
function takes_a(a::A)
println("Took A!")
end
export takes_a
end
function_caller.jl
include("a_function.jl")
include("types.jl")
using TypeModule, AFunctionModule
my_a = A()
takes_a(my_a)
如果您运行julia function_caller.jl
,您将获得MethodError: no method matching takes_a(::TypeModule.A)
。这是因为function_caller.jl中使用的类型A
与a_function.jl中使用的类型不同。在这个简单的例子中,你实际上可以修复"通过颠倒function_caller.jl中包含的顺序(或者只是完全从function_caller.jl中删除include("types.jl")
来解决问题!这不好!)。但是如果你想要另一个文件b_function.jl也使用TypeModule
中定义的类型呢?你必须做一些非常hacky的事情。或者你可以修改你的LOAD_PATH,这样模块只定义一次。
编辑以响应xji:要分发模块,您可以使用Pkg
(docs)。我理解这个问题的前提是一个自定义的个人模块。
顺便提一下,如果您真的不想修改加载路径(即使它只在单个脚本的范围内......),您可以将模块符号链接到包目录中(例如~/.julia/v0.6/MyModule/MyModule.jl
)然后Pkg.add(MyModule)
然后正常导入。我发现这有点麻烦了。
答案 4 :(得分:1)
除非您显式加载文件(include("./Hello.jl")
),否则Julia会在LOAD_PATH变量中定义的目录中查找模块文件。
请参阅this page。
答案 5 :(得分:0)
如果要在使用“using”导入模块时访问函数foo,则需要在模块的标题中添加“export foo”。
答案 6 :(得分:0)
我有Julia Version 1.4.2 (2020-05-23)
。只是这个using .Hello
对我有用。
但是,我不得不在using .Hello
之前编译Hello模块。对于Hello
的定义和使用脚本都在同一文件中,这是很有意义的。
相反,我们可以在一个文件中定义Hello
,然后通过include("./Hello.jl");using .Hello
在另一个文件中使用它