Нет «официального» способа сделать это, и я бы сказал, что если вы думаете, что на самом деле нужно , чтобы сделать это, вы делаете что-то не так и должны задать еще один вопрос о том, как достичь цель, которую вы хотите достичь. Таким образом, этот ответ предлагается в духе игривости и исследования, в надежде, что он распространяет некоторые интересные знания о виртуальной машине Erlang / Elixir.
Существует функция erts_debug:size/1
, которая сообщает, сколько «слов» памяти занимает термин Эрланг / Эликсир. В этой таблице указано, сколько слов используют различные термины. В частности, кортеж использует 1 слово, плюс 1 слово для каждого элемента, плюс место для хранения любых элементов, которые не являются непосредственными. Мы используем маленькие целые числа в качестве элементов, и они являются «немедленными» и, следовательно, «свободными». Итак, это проверено:
> :erts_debug.size({1,2})
3
Теперь давайте создадим кортеж, содержащий два из этих кортежей:
> :erts_debug.size({{1,2}, {1,2}})
9
Это имеет смысл: два внутренних кортежа - это 3 слова в каждом, а внешний кортеж - 1 + 2 слова, всего 9 слов.
Но что, если мы поместим внутренний кортеж в переменную?
> x = {1, 2}
{1, 2}
> :erts_debug.size({x, x})
6
Смотри, мы сохранили 3 слова! Это потому, что содержимое x
считается только один раз; внешний кортеж дважды указывает на один и тот же внутренний кортеж.
Итак, давайте напишем небольшую функцию, которая сделает это за нас:
defmodule Test do
def same?(a, b) do
a_size = :erts_debug.size(a)
b_size = :erts_debug.size(b)
# Three words for the outer tuple; everything else is shared
a_size == b_size and :erts_debug.size({a,b}) == a_size + 3
end
end
Система работает? Кажется, будет:
> Test.same? x, {1,2}
false
> Test.same? x, x
true
Цель достигнута!
Однако, скажем, мы пытаемся вызвать эту функцию из другой функции в скомпилированном модуле, а не из оболочки iex:
def try_it() do
x = {1, 2}
a1 = {"a", {1, 2}}
a2 = {"a", {1, 2}}
a3 = {"a", x}
IO.puts "a1 and a2 same? #{same?(a1,a2)}"
IO.puts "a1 and a3 same? #{same?(a1,a3)}"
IO.puts "a3 and a2 same? #{same?(a3,a2)}"
end
что печатает:
> Test.try_it
a1 and a2 same? true
a1 and a3 same? true
a3 and a2 same? true
Это потому, что компилятор достаточно умен, чтобы видеть, что эти литералы равны, и объединяет их в один термин во время компиляции.
Обратите внимание, что это совместное использование терминов теряется, когда термины отправляются другому процессу или сохраняются в / извлекаются из таблицы ETS. Подробнее см. раздел «Сообщения процесса» в Руководстве по эффективности Erlang .