Заметные отличия от других языков
Заметные различия от MATLAB
Хотя пользователи MATLAB могут найти синтаксис Julia знакомым, Julia не является клоном MATLAB. Существуют значительные синтаксические и функциональные различия. Ниже приведены некоторые заметные отличия, которые могут сбить с толку пользователей Julia, привыкших к MATLAB:
- Массивы Julia индексируются с помощью квадратных скобок,
A[i,j]. - Массивы Julia присваиваются по ссылке. После
A=B, изменение элементовBизменит иA. - Значения Julia передаются и присваиваются по ссылке. Если функция изменяет массив, изменения будут видны в вызывающей функции.
- Julia не увеличивает массивы автоматически в операторе присваивания. В то время как в MATLAB
a(4) = 3.2может создать массивa = [0 0 0 3.2]иa(5) = 7может увеличить его доa = [0 0 0 3.2 7], соответствующее оператор Juliaa[5] = 7вызовет ошибку, если длинаaменьше 5 или если это первое использование идентификатораa. Julia имеетpush!()иappend!(), которые увеличиваютVectorнамного эффективнее, чемa(end+1) = valMATLAB. - Мнимая единица
sqrt(-1)представлена в Julia какim, а неiилиjкак в MATLAB. - В Julia целочисленные литералы без десятичной точки (например,
42) создают целые числа вместо чисел с плавающей точкой. Поддерживаются целочисленные литералы произвольно большой величины. В результате некоторые операции, такие как2^-1, выбросят ошибку домена, так как результат не является целым числом (см. статью FAQ об ошибках домена для подробностей). - В Julia несколько значений возвращаются и присваиваются как кортежи, например,
(a, b) = (1, 2)илиa, b = 1, 2. MATLAB’snargout, который часто используется в MATLAB для выполнения дополнительных задач в зависимости от количества возвращаемых значений, не существует в Julia. Вместо этого пользователи могут использовать необязательные и ключевые аргументы для достижения аналогичных возможностей. - Julia имеет истинные одномерные массивы. Столбцовые векторы имеют размер
N, а неNx1. Например,rand(N)создаёт одномерный массив. - В Julia v0.3 конкатенация скаляров и массивов с синтаксисом
[x,y,z]выполняется по первой размерности («по вертикали»). Для конкатенации по второй размерности («по горизонтали») используйте пробелы, как в[x y z]. Для построения блочных матриц (конкатенация по двум первым размерностям) используется синтаксис[a b; c d]для избежания путаницы. В Julia v0.4 синтаксис конкатенации[x, [y, z]]устарел в пользу синтаксиса[x; [y, z]]. - В Julia
a:bиa:b:cсоздают объектыRange. Для создания полного вектора, как в MATLAB, используйтеcollect(a:b). Обычно вызыватьcollectнет необходимости.Rangeв большинстве случаев будет вести себя как обычный массив, но является более эффективным, так как вычисляет свои значения лениво. Этот паттерн создания специализированных объектов вместо полных массивов часто используется и встречается в функциях, таких какlinspace, или с итераторами, такими какenumerate, иzip. Специализированные объекты в основном могут использоваться как обычные массивы. - Функции в Julia возвращают значения из последнего выражения или ключевого слова
returnвместо перечисления имён переменных для возврата в определении функции (см. Ключевое слово return для подробностей). - Сценарий Julia может содержать любое количество функций, и все определения будут видны снаружи при загрузке файла. Определения функций можно загружать из файлов вне текущей рабочей директории.
- В Julia функции-редукции, такие как
sum(),prod()иmax(), выполняются над каждым элементом массива при вызове с одним аргументом, как вsum(A), даже еслиAимеет более одной размерности. - В Julia функции, такие как
sort(), которые по умолчанию работают по столбцам (sort(A)эквивалентноsort(A,1)) не имеют специального поведения для массивов1xN; аргумент возвращается без изменений, так как он всё ещё выполняетsort(A,1). Чтобы отсортировать матрицу1xNкак вектор, используйтеsort(A,2). - В Julia, если
Aявляется двумерным массивом,fft(A)вычисляет 2D-преобразование Фурье. В частности, это не эквивалентноfft(A,1), которое вычисляет 1D-преобразование Фурье по столбцам. - В Julia для вызова функции с нулевыми аргументами необходимо использовать скобки, как в
tic()иtoc(). - В Julia не рекомендуется использовать точки с запятой для завершения операторов. Результаты операторов не выводятся автоматически (за исключением интерактивного приглашения), и строки кода не должны заканчиваться точкой с запятой.
println()или@printf()можно использовать для вывода определенного вывода. - В Julia, если
AиBявляются массивами, логические операции сравнения, такие какA == B, не возвращают массив булевых значений. Вместо этого используйтеA .== B, и аналогично для других булевых операторов, таких как<,>и=. - В Julia операторы
&,|и$выполняют побитовые операции, эквивалентныеand,orиxorсоответственно в MATLAB, и имеют приоритет, аналогичный побитовым операторам Python (в отличие от C). Они могут работать со скалярами или поэлементно с массивами и могут использоваться для объединения логических массивов, но обратите внимание на разницу в порядке операций: могут потребоваться скобки (например, для выбора элементовAравных 1 или 2, используйте(A .== 1) | (A .== 2)). - В Julia элементы коллекции могут передаваться в качестве аргументов функции с помощью оператора splat
..., как вxs=[1,2]; f(xs...). - Julia’s
svd()возвращает сингулярные значения как вектор, а не как плотную диагональную матрицу. - В Julia
...не используется для продолжения строк кода. Вместо этого незавершенные выражения автоматически продолжаются на следующей строке. - И в Julia, и в MATLAB переменная
ansустанавливается в значение последнего выполненного выражения в интерактивной сессии. В Julia, в отличие от MATLAB,ansне устанавливается при выполнении кода Julia в неинтерактивном режиме. - Структуры данных Julia
typeне поддерживают динамическое добавление полей во время выполнения, в отличие от MATLAB’sclasses. Вместо этого используйтеDict. - В Julia каждый модуль имеет собственное глобальное пространство имен/пространство имён, в то время как в MATLAB существует только одно глобальное пространство имён.
- В MATLAB привычным способом удаления нежелательных значений является использование логической индексации, например, в выражении
x(x>3)или в оператореx(x>3) = []для измененияxна месте. В отличие от этого, Julia предоставляет функции высшего порядкаfilter()иfilter!(), позволяющие пользователям писатьfilter(z->z>3, x)иfilter!(z->z>3, x)в качестве альтернатив соответствующим перечислениямx[x.>3]иx = x[x.>3]. Использованиеfilter!()сокращает использование временных массивов. - Аналог извлечения (или «дерейференцирования») всех элементов массива ячеек, например, в
vertcat(A{:})в MATLAB, записывается с использованием оператора splat в Julia, например, какvcat(A...).
Заметные различия от R
Одна из целей Julia — предоставить эффективный язык для анализа данных и статистического программирования. Для пользователей, переходящих из R в Julia, это некоторые заметные различия:
- Одинарные кавычки в Julia используются для заключения символов, а не строк.
- В Julia можно создавать подстроки, индексируя строки. В R строки необходимо преобразовать в векторы символов перед созданием подстрок.
- В Julia, как и в Python, но в отличие от R, строки могут быть созданы с тройными кавычками
""" ... """. Этот синтаксис удобен для построения строк, содержащих переводы строк. - В Julia аргументы с переменным числом значений (varargs) задаются с помощью оператора splat
..., который всегда следует за именем конкретной переменной, в отличие от R, где...может встречаться изолированно. - В Julia оператор остатка (модуль) это
mod(a, b), а неa %% b.%в Julia — это оператор нахождения остатка. - В Julia не все структуры данных поддерживают логическую индексацию. Более того, логическая индексация в Julia поддерживается только с векторами длины, равной объекту, по которому выполняется индексация. Например: - В R,
c(1, 2, 3, 4)[c(TRUE, FALSE)]эквивалентноc(1,3). - В R,c(1, 2, 3, 4)[c(TRUE, FALSE, TRUE, FALSE)]эквивалентноc(1,3). - В Julia,[1, 2, 3, 4][[true, false]]генерируетBoundsError. - В Julia,[1, 2, 3, 4][[true, false, true, false]]приводит к[1, 3]. - Как и во многих языках программирования, Julia не всегда позволяет выполнять операции над векторами разной длины, в отличие от R, где векторам требуется только общий диапазон индексов. Например,
c(1,2,3,4) + c(1,2)является допустимым кодом R, но эквивалентный[1:4] + [1:2]вызовет ошибку в Julia. - Оператор
apply()в Julia принимает функцию первой, а затем её аргументы, в отличие отlapply(<structure>, function, arg2, ...)в R. - Julia использует
endдля обозначения конца блоков условных операторов, какif, блоков циклов, какwhile/for, и функций. Вместо однострочного оператораif ( cond ) statement, Julia допускает операторы видаif cond; statement; end,cond && statementи!cond || statement. Операторы присваивания в последних двух синтаксических конструкциях должны быть явно заключены в скобки, например,cond && (x = value). - В Julia
<-,<<-и->не являются операторами присваивания. - Оператор
->в Julia создаёт анонимную функцию, как и в Python. - Julia создаёт векторы с использованием квадратных скобок.
[1, 2, 3]в Julia эквивалентенc(1, 2, 3)в R. - Оператор
*в Julia может выполнять умножение матриц, в отличие от R. ЕслиAиB— матрицы, тоA * Bобозначает умножение матриц в Julia, эквивалентноеA %*% Bв R. В R этот же символ обозначает поэлементное (хадамардовое) произведение. Чтобы получить поэлементное умножение, нужно записатьA .* Bв Julia. - Julia выполняет транспонирование матриц с помощью оператора
.'и сопряжённого транспонирования с помощью оператора'.A.'в Julia, таким образом, эквивалентенt(A)в R. - В Julia не нужны скобки при записи операторов
ifили цикловfor/while. Используйтеfor i in [1, 2, 3]вместоfor (i in c(1, 2, 3))иif i == 1вместоif (i == 1). - Julia не рассматривает числа
0и1как булевы значения. Вы не можете написатьif (1)в Julia, потому что операторыifпринимают только булевы значения. Вместо этого можно написатьif true,if Bool(1), илиif 1==1. - Julia не предоставляет
nrowиncol. Вместо этого используйтеsize(M, 1)дляnrow(M)иsize(M, 2)дляncol(M). - Julia тщательно различает скаляры, векторы и матрицы. В R
1иc(1)одинаковы. В Julia их нельзя использовать взаимозаменяемо. Потенциально путающий результат заключается в том, чтоx' * yдля векторовxиy— это вектор из одного элемента, а не скаляр. Чтобы получить скаляр, используйтеdot(x, y). - Функции
diag()иdiagm()в Julia отличаются от аналогичных функций в R. - В Julia нельзя присвоить значение результату вызова функции в левой части оператора присваивания: нельзя написать
diag(M) = ones(n). - В Julia не рекомендуется заполнять основной пространство имён функциями. Большая часть статистических функций Julia находится в пакетах в рамках организации JuliaStats. Например:
- Функции, относящиеся к распределениям вероятностей, предоставляются пакетом Distributions.
- Пакет DataFrames предоставляет структуры данных DataFrames.
- Обобщённые линейные модели предоставляются пакетом GLM.
- Julia предоставляет кортежи и хеш-таблицы, но не списки в стиле R. При возвращении нескольких значений следует использовать кортеж: вместо
list(a = 1, b = 2), используйте(1, 2). - Julia поощряет создание собственных типов данных, которые удобнее использовать, чем S3 или S4 объекты в R. Система множественного диспетчерирования Julia означает, что
table(x::TypeA)иtable(x::TypeB)действуют какtable.TypeA(x)иtable.TypeB(x)в R. - В Julia значения передаются и присваиваются по ссылке. Если функция изменяет массив, изменения будут видны в вызывающей функции. Это сильно отличается от R и позволяет новым функциям работать с большими структурами данных гораздо эффективнее.
- В Julia векторы и матрицы конкатенируются с помощью
hcat(),vcat()иhvcat(), а неc,rbindиcbindкак в R. - В Julia диапазон, как
a:b, не является сокращением для вектора, как в R, но представляет собой специализированный объект, используемый для итерации без высокой загрузки памяти. Чтобы преобразовать диапазон в вектор, используйтеcollect(a:b). - Функции
max()иmin()в Julia эквивалентныpmaxиpminв R соответственно, но оба аргумента должны иметь одинаковые размеры. Хотяmaximum()иminimum()заменяютmaxиminв R, существуют важные различия. sum(),prod(),maximum(), иminimum()в Julia отличаются от своих аналогов в R. Все они принимают один или два аргумента. Первый аргумент — это итерируемая коллекция, такая как массив. Если есть второй аргумент, он указывает на размерность, по которой выполняется операция. Например, пустьA=[[1 2],[3 4]]в Julia иB=rbind(c(1,2),c(3,4))— это одна и та же матрица в R. Тогдаsum(A)даёт тот же результат, что иsum(B), ноsum(A, 1)— это строчный вектор, содержащий сумму по каждому столбцу, аsum(A, 2)— это столбцовый вектор, содержащий сумму по каждой строке. Это отличается от поведения R, гдеsum(B,1)=11иsum(B,2)=12. Если второй аргумент — это вектор, он определяет все размерности, по которым выполняется суммирование, например,sum(A,[1,2])=10. Следует отметить, что проверка второго аргумента отсутствует.- В Julia есть несколько функций, которые могут изменять свои аргументы. Например, есть как
sort(), так иsort!(). - В R для повышения производительности требуется векторизация. В Julia почти наоборот: наилучшая производительность часто достигается с помощью не векторизованных циклов.
- Julia — это жадно оцениваемый язык и не поддерживает ленивую оценку в стиле R. Для большинства пользователей это означает, что неявных выражений или имён столбцов очень мало.
- Julia не поддерживает тип
NULL. - Julia не имеет эквивалента
assignилиgetиз R. - В Julia для
returnне нужны скобки. - В R идиоматический способ удаления нежелательных значений — использование логической индексации, как в выражении
x[x>3]или в оператореx = x[x>3]для измененияxна месте. В отличие от этого, Julia предоставляет высокоуровневые функцииfilter()иfilter!(), позволяя пользователям написатьfilter(z->z>3, x)иfilter!(z->z>3, x)в качестве альтернатив соответствующим переписываниямx[x.>3]иx = x[x.>3]. Использованиеfilter!()снижает использование временных массивов.
Существенные отличия от Python
- В Julia вектор векторов может автоматически конкатенироваться в одномерный вектор если не указан явный тип элементов. Например:
- В Julia,
[1, [2, 3]]конкатенируется в[1, 2, 3], как в R. - В Julia,
Int[1, Int[2, 3]]не будет конкатенироваться, а вместо этого вызовет ошибку. - В Julia,
Any[1, [2,3]]не будет конкатенироваться. - В Julia,
Vector{Int}[[1, 2], [3, 4]]не будет конкатенироваться, но создаст объект, аналогичный списку списков в Python. Этот объект отличается от двумерногоArrayизInt.
- В Julia,
- В Julia для завершения блока требуется
end. В отличие от Python, в Julia нет ключевого словаpass. - В Julia индексация массивов, строк и т. д. основана на 1, а не на 0.
- Индексация срезов в Julia включает последний элемент, в отличие от Python.
a[2:3]в Julia соответствуетa[1:3]в Python. - В Julia не поддерживаются отрицательные индексы. В частности, последний элемент списка или массива индексируется с помощью
endв Julia, а не-1, как в Python. - В Julia списки включений не поддерживают необязательную
if-клаузу, которая есть в Python. - В Julia
for,if,while, и т. д. блоки завершаются ключевым словомend. Уровень отступов не имеет значения, как в Python. - В Julia нет синтаксиса продолжения строки: если в конце строки введенное выражение является полным, то оно считается завершенным; в противном случае ввод продолжается. Один из способов принудительно продолжить выражение — заключить его в скобки.
- Массивы Julia хранятся в порядке следования столбцов (порядке Fortran), тогда как массивы NumPy по умолчанию хранятся в порядке следования строк (порядке C). Для достижения оптимальной производительности при циклическом проходе по массивам порядок циклов в Julia следует изменять относительно NumPy (см. соответствующий раздел Рекомендации по производительности).
- Операторы обновления в Julia (например,
+=,-=, ...) не являются непосредственными, в отличие от NumPy. Это означает, чтоA = ones(4); B = A; B += 3не изменяет значения вA, а скорее привязывает имяBк результату правой частиB = B + 3, что представляет собой новый массив. ИспользуйтеB[:] += 3, явные циклы илиInplaceOps.jl. - Julia вычисляет значения по умолчанию аргументов функций каждый раз при вызове метода, в отличие от Python, где значения по умолчанию вычисляются только один раз при определении функции. Например, функция
f(x=rand()) = xвозвращает новое случайное число каждый раз при вызове без аргументов. С другой стороны, функцияg(x=[1,2]) = push!(x,3)возвращает[1,2,3]каждый раз, когда она вызывается какg(). - В Julia оператор
%является оператором остатка, а в Python — оператором модуля.
Существенные отличия от C/C++
- Массивы Julia индексируются квадратными скобками и могут иметь более одной размерности
A[i,j]. Этот синтаксис не просто синтаксический сахар для ссылки на указатель или адрес, как в C/C++. Обратитесь к документации Julia для синтаксиса построения массивов (он менялся между версиями). - В Julia индексация массивов, строк и т. д. основана на 1, а не на 0.
- Массивы Julia присваиваются по ссылке. После
A=B, изменение элементовBтакже изменитA. Операторы обновления, такие как+=не работают на месте, они эквивалентныA = A + B, которое переприсваивает левую часть результату выражения правой части. - Массивы Julia хранятся в порядке следования столбцов (порядок Fortran), в то время как массивы C/C++ по умолчанию упорядочены по строкам. Для достижения оптимальной производительности при работе с массивами порядок циклов в Julia следует изменить относительно C/C++ (см. соответствующий раздел Рекомендации по производительности).
- Значения Julia передаются и присваиваются по ссылке. Если функция изменяет массив, эти изменения будут видны в вызывающей функции.
- В Julia пробелы имеют значение, в отличие от C/C++, поэтому при добавлении/удалении пробелов из программы Julia следует соблюдать осторожность.
- В Julia целочисленные литералы без десятичной точки (например,
42) создают целые числа со знаком, типаInt, но литералы, слишком большие, чтобы уместиться в размере машинного слова, будут автоматически повышены до типа большего размера, такого какInt64(еслиIntявляетсяInt32),Int128, или произвольно большой типBigInt. Нет суффиксов для числовых литералов, таких какL,LL,U,UL,ULLдля указания беззнаковых и/или со знаком против беззнаковых. Десятичные литералы всегда со знаком, а шестнадцатеричные литералы (которые начинаются с0x, как в C/C++), без знака. Шестнадцатеричные литералы также, в отличие от C/C++/Java и в отличие от десятичных литералов в Julia, имеют тип, основанный на *длине* литерала, включая ведущие нули. Например,0x0и0x00имеют тип UInt8,0x000и0x0000имеют типUInt16, затем литералы с 5 до 8 шестнадцатеричных цифр имеют типUInt32, от 9 до 16 шестнадцатеричных цифр типUInt64, а от 17 до 32 шестнадцатеричных цифр типUInt128. Это необходимо учитывать при определении шестнадцатеричных масок, например,~0xf == 0xf0сильно отличается от~0x000f == 0xfff0. 64-битныеFloat64и 32-битныеFloat32битовые литералы выражаются как1.0и1.0f0соответственно. Вещественные литералы округляются (и не повышаются до типаBigFloat) если их нельзя точно представить. Вещественные литералы ведут себя ближе к C/C++. - Строковые литералы могут быть ограничены либо
"или""","""ограниченные литералы могут содержать"символы без кавычек, как в"\"". Строковые литералы могут содержать значения других переменных или выражений, интерполированные в них, указанные$variablenameили$(expression), которые оценивают имя переменной или выражение в контексте функции. -
//обозначаетRationalчисло, а не однострочный комментарий (который#в Julia) -
#=обозначает начало многострочного комментария, а=#завершает его. - Функции в Julia возвращают значения из их последнего(их) выражения(ий) или ключевого слова
return. От функций можно возвращать несколько значений, которые присваиваются как кортежи, например,(a, b) = myfunction()илиa, b = myfunction(), вместо того, чтобы передавать указатели на значения, как это нужно в C/C++ (т. е.a = myfunction(&b)). - Julia не требует использования точек с запятой для завершения операторов. Результаты выражений не выводятся автоматически (за исключением интерактивного приглашения, т. е. REPL), и строки кода не должны заканчиваться точкой с запятой.
println()или@printf()могут использоваться для вывода определенного вывода. В REPL;можно использовать для подавления вывода.;также имеет другое значение в[ ], что следует учитывать.;могут использоваться для разделения выражений в одной строке, но они не строго необходимы во многих случаях и больше служат для повышения читаемости. - В Julia оператор
$выполняет побитовую операцию XOR, т. е.^в C/C++. Кроме того, побитовые операторы не имеют того же приоритета, что и в C/++, поэтому могут потребоваться скобки. - Оператор Julia
^выполняет возведение в степень (pow), а не побитовое XOR, как в C/C++ (используйте$в Julia) - Julia имеет два оператора правого сдвига,
>>и>>>.>>>выполняет арифметический сдвиг,>>всегда выполняет логический сдвиг, в отличие от C/C++, где значение>>зависит от типа сдвигаемого значения. ->Julia создает анонимную функцию, она не обращается к члену через указатель.- В Julia не нужны скобки при написании операторов
ifили цикловfor/while: используйтеfor i in [1, 2, 3]вместоfor (int i=1; i <= 3; i++)иif i == 1вместоif (i == 1). - Julia не рассматривает числа
0и1как булевы. Вы не можете написатьif (1)в Julia, потому что операторыifпринимают только булевы значения. Вместо этого вы можете написатьif true,if Bool(1), илиif 1==1. - Julia использует
endдля обозначения конца блоков условных операторов, какif, блоков циклов, какwhile/for, и функций. Вместо однострочного оператораif ( cond ) statement, Julia допускает операторы видаif cond; statement; end,cond && statementи!cond || statement. Операторы присваивания в двух последних синтаксических конструкциях должны быть явно заключены в скобки, например,cond && (x = value), из-за приоритета операторов. - В Julia нет синтаксиса продолжения строки: если в конце строки введённое выражение является полным выражением, оно считается завершённым; в противном случае входные данные продолжаются. Один из способов заставить выражение продолжить работу — заключить его в скобки.
- Макросы Julia работают с разобранными выражениями, а не с текстом программы, что позволяет им выполнять сложные преобразования кода Julia. Имена макросов начинаются с символа
@, и они имеют синтаксис, похожий на функцию,@mymacro(arg1, arg2, arg3), и синтаксис, похожий на оператор,@mymacro arg1 arg2 arg3. Формы взаимозаменяемы; форма, похожая на функцию, особенно полезна, если макрос встречается внутри другого выражения, и часто более понятна. Форма, похожая на оператор, часто используется для аннотации блоков, как в параллельномforконструкте:@parallel for i in 1:n; #= body =#; end. Где конец конструкции макроса может быть неясным, используйте форму, похожую на функцию. - Julia теперь имеет тип перечисления, выраженный с помощью макроса
@enum(name, value1, value2, ...)Например:@enum(Fruit, Banana=1, Apple, Pear) - По соглашению, функции, которые изменяют свои аргументы, имеют
!в конце имени, например,push!. - В C++, по умолчанию, используется статическая диспетчеризация, т. е. нужно пометить функцию как виртуальную, чтобы использовать динамическую диспетчеризацию. С другой стороны, в Julia каждый метод является «виртуальным» (хотя это более общее понятие, так как методы диспетчеризуются по каждому типу аргумента, а не только
this, используя правило наиболе-специфичного объявления).
© 2009–2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/release-0.5/manual/noteworthy-differences/