День 1 Летней школы Julia 2025
Введение в кортежи
Рассмотрим синтаксис и некоторые особенности кортежей. Однако их назначение и преимущества рассмотрим в следующих главах.
Кортежи являются неизменяемыми контейнерами фиксированной длины.
Они записываются при помощи круглых скобок, а элементы внутри кортежа перечисляются с помощью запятых.
args = (2+3,'w',"строка")
Обратите внимание, что типом нашего кортежа является отдельный тип - Кортеж из числа, символа и строки.
typeof(args)
Также как и для строк, для кортежей есть синтаксис индексации. Обратившись по 3 индексу нашего кортежа получаем значение "строка".
args[3]
Также как и строки, элементы кортежей нельзя менять.
Давайте разберём, что означат ошибка, которую нам выдаёт компилятор:
MethodError: no method matching setindex!(::Tuple{Int64, Char, String}, ::Int64, ::Int64)
The function setindex! exists, but no method is defined for this combination of argument types.
Когда мы используем квадратные скобки, вызывается функцияsetindex. Также как и когда мы пишем двойное равенство - это не специальный символ, а лишь синоним для функции isequal.
То есть компилятор указывает, что нет функции назначения целочисленного числа по целочисленной индексации для кортежа типа число, символ, строка.
args[1] = 12
Если мы укажем один элемент в скобках, то это будет восприниматься не как кортеж из одного элемента, а как обычный элемент.
x = (1)
typeof(x)
кортеж из 1 элемента прописывается особым образом. Для этого нужно указать элемент, который мы собираемся хранить, и обязательно нужно поставить запятую после него.
x = (1,)
typeof(x)
Также существует специальный, оптимизированный тип кортежей, где хранятся элементы одинакового типа. В этом случае мы получим не кортеж типа Tuple{Int,Int,Int}, как NTuple(5, Int)
typeof((5,4,3,4,5))
Именованные кортежи
Помимо обычных кортежей и NTuple, в Julia есть и именованные кортежи.
Этот тип данных позволяет обращаться к элементам массива по имени, связанным с элементом.
Именованные кортежи задаются как обычные кортежи, только перед значением элемента задаётся имя, которое будет связано с элементом и ставится знак равно.
А для того чтобы получить значение элемента по имени, необходимо воспользоваться обращением через точку после названия переменной, и указать имя поля.
point = (x=1,y=2,z=3)
point.z
Но помимо обращения по имени, также работает и классическая числовая индексация.
point[2]
Ещё можно столкнуться с синтаксисом, где после точки с запятой перечисляются переменные
a = 1
b = 2
nt = (; a, b)
Последним вариантом задания именованного кортежа рассмотрим следующую запись.
langs = (; :en => "Английский", :ru => "Русский")
langs.en
Что обозначает символ => мы обсудим, когда будем знакомиться со словарями и парами.
Значение символа двоеточие мы оставим за рамками школы, но укажем,
что это связано с понятиями выражения, символа и абстрактного синтаксического дерева.
Обмен значениями
Но теперь предлагаю на секунду отвлечься и посмотреть, как происходит идиоматический,
то есть характерным образом для языка, обмен значениями переменных в С и С++.
В языке Си для этого вводится третья переменная, а в C++ применяется функция swap из стандартной библиотеки.
Си:
a = 1; b = 2;
temp = a;
a = b;
b = temp;
С++
std::swap(a,b);
В Julia, как и в Python, есть параллельное или "разрушающее" присваивание.
Здесь a станет равно 1, а b = 2.
a, b = 1, 2
Поэтому идеоматический обмен значениями будет выглядеть следующим образом:
a, b = b, a
a
Более того, это присваивание работает для всех типов, поддерживающих итерирование.
Таких например, как диапазон
a, b, c = 5:9
c
Или уже знакомая нам строка.
a,b,c = "ABCDEF"
b
Если мы не хотим засорять пространство имён лишними переменными, то можно воспользоваться "заглушкой" в виде нижнего подчёркивания.
Тогда в тех местах, на которых стоят эти заглушки, итератор выполнит свой шаг.
a, _, b = 10:12
print(a,' ', b)
Это может быть полезно, например, в таком случае
# import Pkg; Pkg.add("Dates")
using Dates
yearmonthday(now())
_, месяц, день = yearmonthday(now())
месяц
monthday(now())