Julia 朱莉娅:“导入”和“使用”的用例`

Julia 朱莉娅:“导入”和“使用”的用例`,julia,Julia,所以我读了朱莉娅的书。然而,这并没有告诉我应该如何在实践中使用这两个语句(而且,考虑到缺乏正交性,这并不太容易) 举个例子:让我们在“myfile.jl”中放入以下琐碎的代码: 如果在最后一行使用import,则f不会导出到Main命名空间。但是,当我更改“myfile.jl”(例如修改f的返回值)然后重新包含它时,该函数将被替换(这是我希望的行为)。(请注意,我可以显式地导入.MyModule:f,但这会引入不必要的冗余;而且,现实生活中的情况将涉及一长串具有长名称的函数。好的,我也可以编写

所以我读了朱莉娅的书。然而,这并没有告诉我应该如何在实践中使用这两个语句(而且,考虑到缺乏正交性,这并不太容易)

举个例子:让我们在
“myfile.jl”
中放入以下琐碎的代码:

  • 如果在最后一行使用
    import
    ,则
    f
    不会导出到
    Main
    命名空间。但是,当我更改
    “myfile.jl”
    (例如修改
    f
    的返回值)然后重新包含它时,该函数将被替换(这是我希望的行为)。(请注意,我可以显式地
    导入.MyModule:f
    ,但这会引入不必要的冗余;而且,现实生活中的情况将涉及一长串具有长名称的函数。好的,我也可以编写一个使用
    名称(Main.MyModule)
    的宏,但我不知何故觉得这应该更简单。)

  • 如果使用替换
    导入
    ,则情况相反:
    f
    现在导出,但更改模块中的任何内容都需要重新启动Julia解释器

  • 同时使用
    import
    using
    只将
    f()
    的第一个版本导出到主命名空间:当我更新代码时,只使用第一个返回值

因此,我的问题不是关于
import
using
这两个语句的行为,它们都记录在链接页面中(如果没有解释的话),而是关于它们背后的意图。一句话就够了,为什么还要说两句?为什么其中一个会忽略所有
export
指令?在哪种情况下,我应该在实践中使用每一个语句


(版本是1.1.0。此外,它在没有easy
Pkg
访问权限的系统上运行,因此我还没有尝试
Revision

Julia中的惯例是使用
使用PackageName
,除非您有特定的理由这样做

这种语言设计决策仅仅是出于用户的舒适感。Julia使用多个分派,通常包导出对类型化参数进行操作的函数(但这些参数通常是
抽象类型,因此函数功能不受限制)

在这种设计中,实现它们的所有函数和方法都可以位于同一名称空间中,因为它们在特定于其包的参数类型上有所不同。因此,
使用
将覆盖现有方法实现的包带到命名空间的场景非常罕见(然后Julia报告警告)。此过程由包作者通过使用
export
关键字进行额外控制

我认为这对您来说很奇怪,因为您已经习惯了Python之类的语言。例如,
numpy
具有与默认函数完全相同的函数名,并且没有好的方法对它们进行不同的命名(例如,尝试想想对于名为
sin
:-)的函数,什么是好的替代方法)。因此,在Python中,您总是需要将函数导入到它们自己的名称空间中,可能需要使用一个别名,例如
import numpy as np
。在对两种语言都有了几年的经验之后,我想说朱莉娅这样做是很自然的,而Pytonish的方式是很奇怪的:-)


关于
import
以及将单个函数从包中引入命名空间的可能性,我将其视为发生名称冲突的情况下的变通方法。如果您想向其他包中添加新的方法实现(比如为
+
操作符定义新的含义),那么还需要显式地这样做。除此之外,您只需使用
键入
,并且永不回头。

除了Przemyslaw Szufel的答案之外,还有一点需要补充。当您扩展一个方法时,可以在不使用所扩展函数的
import
的情况下进行扩展。例如,如果我想从模块
Foo
扩展
f
,我可以使用Foo
执行
,然后为
Foo.f
定义一个新方法。下面是一个完整的示例:

module Foo
    struct A
        x::Int
    end

    f(a::A) = a.x + 1

    export A, f
end

using .Foo

struct B
    x::Int
end

Foo.f(b::B) = b.x + 2

这种方法的优点是,当您阅读代码时,更容易看到您正在扩展的函数的起源。

为什么在使用.Foo
中有一个点?
Foo
Main
的命名空间中声明,而不是在它自己的包中声明
using.Foo
是使用Main.Foo
BTW的一个较短版本,在此代码中编写
import.Foo
就足够了,尽管
在这里使用
更自然。如果这个代码在一个包中,我宁愿使用
import
。通常在实际代码中,您也希望在没有限制的情况下使用
Foo
中的一些函数。换句话说,我通常有这样的代码:在一个部分中,我使用
Foo.blah()
而没有限定,即只使用
blah()
,然后我需要从
Foo
扩展一个函数
bar
,然后我扩展限定的形式
Foo.bar
@Cameron Bieganek我同意:-)
module Foo
    struct A
        x::Int
    end

    f(a::A) = a.x + 1

    export A, f
end

using .Foo

struct B
    x::Int
end

Foo.f(b::B) = b.x + 2