Заметные отличия от других языков
Заметные отличия от 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
[x,y,z]всегда создает массив из 3 элементов, содержащихx,yиz.Для конкатенации по первому ("вертикальному") измерению используйте либо
vcat(x,y,z), либо разделяйте точкой с запятой ([x; y; z]).Для конкатенации по второму ("горизонтальному") измерению используйте либо
hcat(x,y,z), либо разделяйте пробелами ([x y z]).Для создания блочных матриц (конкатенация по двум первым измерениям) используйте либо
hvcat(), либо сочетание пробелов и точек с запятой ([a b; c d]).
В 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, операторы
&,|и⊻(xor) выполняют побитовые операции, эквивалентные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 не поддерживают динамическое добавление полей во время выполнения, в отличие от структур MATLAB. Вместо этого используйте
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) задаются с использованием оператора разброса
..., который всегда следует за именем конкретной переменной, в отличие от 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, 2, 3, 4] + [1, 2]вызовет ошибку в Julia.Функция
map()в Julia принимает функцию первой, а затем её аргументы, в отличие отlapply(<structure>, function, ...)в R. Аналогично, эквивалентapply(X, MARGIN, FUN, ...)в R в Julia — этоmapslices(), где функция является первым аргументом.Многомерное применение в R, например,
mapply(choose, 11:13, 1:3), можно записать какbroadcast(binomial, 11:13, 1:3)в Julia. Аналогично, Julia предлагает более короткий точечный синтаксис для векторизации функцийbinomial.(11:13, 1:3).Julia использует
endдля обозначения конца блоков условных операторов, какif, циклов, какwhile/for, и функций. Вместо однострочногоif ( cond ) statementJulia допускает операторы вида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 тот же самый оператор выполнит поэлементное (Хэдэмэрдовое) произведение. Чтобы получить поэлементное умножение, в Julia нужно написатьA .* B.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 они не могут быть использованы взаимозаменяемо.В Julia нельзя присвоить значение результату вызова функции в левой части оператора присваивания: нельзя написать
diag(M) = ones(n).-
В Julia не рекомендуется заполнять главный пространство имён функциями. Большинство статистических функций Julia находятся в пакетах в рамках организации JuliaStats. Например:
Функции, относящиеся к распределениям вероятностей, предоставляются пакетом Distributions.
Пакет DataFrames предоставляет структуры данных DataFrame.
Обобщённые линейные модели предоставляются пакетом 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, а является специализированнымRange, используемым для итерации без высокой нагрузки на память. Для преобразования диапазона в вектор используйте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 требует
endдля завершения блока. В отличие от Python, в Julia нет ключевого словаpass.В Julia индексация массивов, строк и т. д. основана на 1, а не на 0.
Индексация срезов в Julia включает последний элемент, в отличие от Python.
a[2:3]в Julia соответствуетa[1:3]в Python.Julia не поддерживает отрицательные индексы. В частности, последний элемент списка или массива индексируется с помощью
endв Julia, а не-1, как в Python.Блоки
for,if,whileи т. д. в Julia завершаются ключевым словомend. Уровень отступа не имеет значения, как в Python.В Julia нет синтаксиса продолжения строк: если в конце строки введенное выражение является полным, оно считается завершенным; в противном случае ввод продолжается. Один из способов заставить выражение продолжить — заключить его в скобки.
Массивы Julia являются столбцово-главными (упорядоченными по Фортрану), тогда как массивы 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++. Восьмеричные (с префиксом0o) и двоичные (с префиксом0b) литералы также обрабатываются как беззнаковые.Строковые литералы могут быть ограничены либо
"или""","""ограниченные литералы могут содержать"символы без их цитирования, например,"\"". Строковые литералы могут содержать значения других переменных или выражений, интерполированных в них, что указывается$variablenameили$(expression), которые оценивают имя переменной или выражение в контексте функции.//обозначаетRationalчисло, а не однострочный комментарий (который является#в Julia).#=обозначает начало многострочного комментария, а=#завершает его.Функции в Julia возвращают значения из последнего выражения(ий) или ключевого слова
return. Из функций можно возвращать несколько значений и присваивать их как кортежи, например,(a, b) = myfunction()илиa, b = myfunction(), вместо того, чтобы передавать указатели на значения, как это необходимо в C/C++ (то есть,a = myfunction(&b)).Julia не требует использования точки с запятой для завершения операторов. Результаты выражений не выводятся автоматически (за исключением интерактивного приглашения, т. е. REPL), и строки кода не должны заканчиваться точкой с запятой.
println()или@printf()можно использовать для вывода определенного вывода. В REPL;можно использовать для подавления вывода.;также имеет другое значение в[ ], на что следует обратить внимание.;может использоваться для разделения выражений в одной строке, но в большинстве случаев это не строго необходимо и является скорее средством повышения удобочитаемости.В Julia оператор
⊻(xor) выполняет побитовое XOR-действие, т. е.^в C/C++. Кроме того, приоритет побитовых операторов отличается от C/++, поэтому могут потребоваться скобки.Оператор Julia
^— возведение в степень (pow), а не побитовое XOR, как в C/C++ (используйте⊻илиxorв 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 ) statementJulia позволяет использовать операторы вида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.6/manual/noteworthy-differences/