Пакеты, модули
В версии Julia v0.5 система пакетов выглядит как прототип, далекий от окончательного вида, но дающий возможность быстро начать работать. В разработке находится следующая версия менеджера пакетов (рабочее название Pkg3), которая придет на смену в будущем. Воспринимайте текущую реализацию как нечто временное.
Установка пакетов
Пакет - это набор файлов содержащих код, тесты и мета-информацию о модуле или модулях, если их несколько. Модуль же - это отдельное пространство имен (в терминах языка).
Установить пакет можно так:
Pkg.add("Имя пакета")
Примечание.
Имя пакета должно быть зарегистрировано в https://github.com/JuliaLang/METADATA.jl, чтобы менеджер пакетов с настройками по умолчанию, автоматически нашел и установил пакет.
Незарегистрированные пакеты можно установить так:
Pkg.clone(url)
В своих программах вы можете автоматизировать проверку и установку какого-либо пакета таким способом:
# Если пакет Lazy не установлен - установить его:
isdir( Pkg.dir("Lazy")) || Pkg.add("Lazy")
Удалить пакет можно командойPkg.rm()
:
# удаление пакета Lazy:
Pkg.rm("Lazy")
include
include выполняет указанный файл, как часть текущего модуля. Используется, чтобы разбить длинный файл на несколько или чтобы иметь доступ к одному куску кода из нескольких файлов.
Нужно иметь ввиду, что когда include
выполняет код из указанного файла - это не является равносильным вставке кода в место вызова include
: вносимые им изменения видны в текущей динамической глобальной области видимости, т.е. в области видимости модуля, который был текущим в момент выполнения инструкции include
, не зависимо от текущей лексической области видимости из которой, возможно, вызвана include
. Пример:
shell> echo "a = 2" > a.jl # теперь файл a.jl содержит код: a = 2
julia> module AA
function aa()
include("a.jl")
end
end
AA
julia> module BB
import AA
function bb()
AA.aa()
end
bb() # вызов
end
BB
julia> BB.a
2
Как видно из примера, несмотря на то, что include
была вызвана в лексической области видимости внутри функции f
модуля AA
из лексической области функции bb (модуля BB), областью видимости переменной a
стала глобальная область - область модуля BB
. Он был текущей динамической глобальной областью в момент выполнения include
.
Инструкция include
выполняется столько раз, сколько раз через нее пройдет поток управления (в отличие от import
и use
). Таким образом, если кусок кода будет повторяться , то во второй и последующие разы вы получите предупреждение о переопределении того, что определяется в подключаемом файле. Значит, вы должны самостоятельно позаботиться о том, когда и сколько раз вы подключите файл.
Вследствие своей динамичной природы include
позволяет подключать файл, имя которого становится известно только во время выполнения программы. Это можно использовать как один из способов внедрения зависимости:
julia> code = """
" тестовый модуль "
module AAA
"функция сложения"
f(x::Int, y::Int) = x+y
end # of module
""";
shell> echo "$code" > file1.jl
julia> where_functions = "file1.jl"
"file1.jl"
julia> dinamic_module = where_functions |> include
AAA
julia> dinamic_module |> typeof
Module
julia> dinamic_module.f( 3, 4)
7
# Как побочный эффект - модуль AAA становится доступен и по имени:
julia> AAA.f(3,4)
7
using и import:
Две похожие по своему действию инструкции. Проще запомнить их различие, чем схожие черты: кроме своего основного назначения, import
позволяет функцию, определенную в другом модуле, расширить по ее короткому имени. Говоря "расширить", я имею ввиду определить в текущем модуле еще один метод для уже определенной функции (определенной, как правило, не в текущем модуле).
Если, в чужом коде вам встретилась инструкция import модуль.имя_функции
, то можно ожидать, что эта функция будет расширена ниже. (Но не обязательно.) Видимо, это сделано, чтобы уменьшить вероятность случайного переопределения существующих имен.
using
же используется, когда вы просто хотите использовать (от "use") модуль, не меняя его определений.
Если Module1
экспортирует fun1(x)
но не экспортирует fun2(x),
module BB
export aa; aa(x)=x*2
bb(x)=x/2
end
то:
действие | после этого можно... | нельзя... |
---|---|---|
import BB | BB.aa(x), BB.bb(x) | aa(x), bb(x), aa(x,y)=x+y |
import BB.aa | aa(x); aa(x,y)=x+y | bb(x); bb(x,y)=x-y |
import BB: aa, bb | aa(x); aa(x,y)=x+y; bb(x); bb(x,y)=x-y | |
using BB | aa(x); BB.aa(x,y)=x+y; BB.bb(x); BB.bb(x,y)=x-y | aa(x,y)=x+y; bb(x,y)=x-y |
importall BB | aa(x); aa(x,y)=x+y; BB.bb(x); BB.bb(x,y)=x-y | bb(x); bb(x,y)=x-y |
Написанный самостоятельно файл модуля должен выполнять перечисленные ниже условия, чтобы using
или import
могли найти его:
имя файла модуля должно заканчиваться на .jl
julia ищет модули в директориях, перечисленных в переменной-массиве LOAD_PATH
julia ищет файлы в этих каталогах в виде ИмяМодуля/src/file.jl
LOAD_PATH - массив строк - путей поиска модулей
Добавить свой путь можно так:
push!(LOAD_PATH, "/Path/To/My/Module/")
... или определить переменную окружения JULIA_LOAD_PATH до запуска julia.