#erlang #tuples #record #ets
#erlang #Кортежи #запись #ets
Вопрос:
Я слышал, что указание записей через кортежи в коде — плохая практика: я всегда должен использовать record fields ( #record_name{record_field = something}
) вместо обычных кортежей {record_name, value1, value2, something}
.
Но как мне сопоставить запись с таблицей ETS? Если у меня есть таблица с записями, я могу сопоставить только со следующим:
ets:match(Table, {$1,$2,$3,something}
Очевидно, что как только я добавлю несколько новых полей в определение записи, это сопоставление с шаблоном перестанет работать.
Вместо этого я хотел бы использовать что-то вроде этого:
ets:match(Table, #record_name{record_field=something})
К сожалению, он возвращает пустой список.
Ответ №1:
Причиной вашей проблемы является то, на что устанавливаются неопределенные поля, когда вы выполняете a #record_name{record_field=something}
. Это синтаксис для создания записи, здесь вы создаете запись / кортеж, который ETS будет интерпретировать как шаблон. Когда вы создаете запись, все неуказанные поля получат свои значения по умолчанию, либо те, которые определены в определении записи, либо значение по умолчанию по умолчанию undefined
.
Итак, если вы хотите присвоить полям конкретные значения, вы должны явно сделать это, например, в записи #record_name{f1='$1',f2='$2',record_field=something}
. Часто при использовании записей и ets вы хотите установить для всех неопределенных полей '_'
значение «не волнует переменная» для сопоставления ets. Для этого существует специальный синтаксис, использующий специальное и в противном случае недопустимое имя поля _
. Например #record_name{record_field=something,_='_'}
.
Обратите внимание, что в вашем примере вы установили для элемента имени записи в кортеже значение ‘$ 1’. Кортеж, представляющий запись, всегда имеет имя записи в качестве первого элемента. Это означает, что при создании таблицы ets вы должны установить ключевую позицию с {keypos,Pos}
чем-то отличным от значения по умолчанию 1
, иначе индексации не будет, и, что еще хуже, если у вас есть таблица типа ‘set’ или ‘ordered_set’, вы получите только 1 элемент в таблице. Чтобы получить индекс поля записи, вы можете использовать синтаксис #Record.Field
, приведенный в вашем примере #record_name.record_field
.
Комментарии:
1. После этого примера:
#record_name{f1='$1',f2='$2',record_field=something}
вы привели пример:#record_name{record_field=something,_='_'}.
Это заставляет думать, что запись_='_'
один раз будет соответствовать всем остальным полям — но в моих попытках вы должны писать_='_'
для каждого дополнительного поля. Это означает, что если вы измените определение записи, чтобы в ней было больше или меньше полей, вам также придется изменить спецификацию соответствия, что, очевидно, не идеально. Одна приятная вещь: вам не нужно указывать поле, которое вы сопоставляете, напримерrecord_field=something
, в правильной позиции в кортеже…2. … Вы можете сначала указать поле, которое вы сопоставляете, а затем следовать за ним с правильным номером
_='_'
. Например, с этим определением записи-record(user, {id, name, city})
вы можете использовать шаблон, подобный этому#user{city="London", _='_', _='_'}
.
Ответ №2:
Попробуйте использовать
ets:match(Table, #record_name{record_field=something, _='_'})
Смотрите Это для объяснения.
Комментарии:
1. В последней версии OTP (24) ets:match/2 не работает таким образом, но ets:match_object/2 работает нормально.
Ответ №3:
Формат, который вы ищете, это #record_name{record_field=something, _ = ‘_’}
http://www.erlang.org/doc/man/ets.html#match-2
http://www.erlang.org/doc/programming_examples/records.html (см. раздел 1.3 Создание записи)