Как сопоставить ets: сопоставить с записью в Erlang?

#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 Создание записи)