
Я потратил около пяти часов (!) на изучениеКак создать команду с ключевыми значениями?(и другие ресурсы) и пытаюсь понять, как реализовать ключевые значения, и это крайне запутанно. Я написал по сути тривиальный (для большинства людей здесь, во всяком случае) тестовый случай, и в нем есть некоторые несоответствия, которые я не могу объяснить.
Вот MWE с использованием keyval
.
% !TEX TS-program = lualatexmk
% !TEX encoding = UTF-8 Unicode
\documentclass{article}
\usepackage{keyval}
\makeatletter
% Key definitions
\define@key{sayhello}{towhom}{\def\sh@towhom{#1}}
% Key defaults
\setkeys{sayhello}{towhom=Michael}
% Define the command that uses the key
\newcommand{\sayhello}[2][]{%
%\begingroup% localizes the new settings w/o calling the defaults
\setkeys{sayhello}{towhom=Michael} % Reset defaults w/o localizing
\setkeys{sayhello}{#1} % Set new keys
Say hello to \sh@towhom\ #2.
%\endgroup%
}%
\makeatother
\begin{document}
\sayhello{tomorrow}
%\sayhello[towhom]{today} % throws no value specified for towhom
\sayhello[towhom=Jill]{tomorrow}
%\sayhello[towhom]{today} % throws no value specified for towhom
\sayhello[towhom=Joe]{tomorrow}
%\sayhello[towhom]{tomorrow} % throws no value specified for towhom
\sayhello{today}
\end{document}
А вот MWE с использованием pgfkeys
.
% !TEX TS-program = lualatexmk
% !TEX encoding = UTF-8 Unicode
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{%
/sayhello/.is family, /sayhello,
towhom/.default=Michael,
towhom/.store in=\sayto
}%
\newcommand*{\sayhello}[2][]{%
\pgfkeys{/sayhello,#1}
Say hello to \sayto\ #2.
}%
\begin{document}
%\sayhello{tomorrow} % throws undefined control sequence
\sayhello[towhom]{today}
\sayhello[towhom=Jill]{tomorrow}
\sayhello[towhom]{today}
\sayhello[towhom=Joe]{tomorrow}
\sayhello[towhom]{tomorrow}
\sayhello{today} % works perfectly
\end{document}
Я надеялся, что обе реализации дадут одинаковые результаты. Они этого не делают. keyval
похоже, не любит указывать ключ без значения. pgfkeys
ведет себя непоследовательно, когда вообще не указано никаких параметров, но ведет себя идеально в случаях, когда keyval
их нет. Мои примеры неправильно закодированы? Являются ли несоответствия ожидаемым поведением? Я совершенно запутался.
решение1
Вы путаете начальное значение и значение по умолчанию. Второе используется, если вы используете ключ без указания значения. Кроме того, если вы используете команду для сохранения значения ключа, хорошей практикой будет сначала определить его с помощью \newcommand
, так как это позволит избежать перезаписи существующих команд.
Лично я нахожуpgfkeys
более запутанным, так как в этом случае используется одна и та же команда для определения и установки ключей, а понимание поведения некоторых обработчиков не всегда легко, см., например,Что делают обработчики ключей pgfkeys .get и .store?.
\documentclass{article}
\usepackage{keyval}
\makeatletter
\newcommand\sh@towhom{}
\define@key{sayhello}{towhom}[Default]{\def\sh@towhom{#1}}
\setkeys{sayhello}{towhom=Initial}
\newcommand{\sayhello}[2][]{%
\begingroup
\setkeys{sayhello}{#1} % Set new keys
keyval, say hello to \sh@towhom\ #2.
\endgroup%
}%
\makeatother
\usepackage{pgfkeys}
\newcommand\sayto{}
\pgfkeys{%
/sayhello/.is family, /sayhello,
towhom/.store in=\sayto,
towhom/.default=Default,
towhom = Initial,
}%
\newcommand*{\sayhellopgf}[2][]{%
\begingroup
\pgfkeys{/sayhello,#1}%
pgfkeys, say hello to \sayto\ #2.
\endgroup
}%
\ExplSyntaxOn
\tl_new:N \l_sayhello_towhom_tl
\keys_define:nn {sayhello}
{
towhom .tl_set:N = \l_sayhello_towhom_tl,
towhom .initial:n = Initial,
towhom .default:n = Default
}
\NewDocumentCommand\sayhelloexpl{O{}m}
{
\group_begin:
\keys_set:nn{sayhello}{#1}
l3keys,~say~hello~to~\l_sayhello_towhom_tl\c_space_tl#2
\group_end:
}
\ExplSyntaxOff
\begin{document}
\sayhello{tomorrow}
\sayhello[towhom]{today}
\sayhello[towhom=Jill]{tomorrow}
\sayhello[towhom]{today}
\sayhello[towhom=Joe]{tomorrow}
\sayhello[towhom]{tomorrow}
\sayhello{today}
\sayhellopgf{tomorrow}
\sayhellopgf[towhom]{today}
\sayhellopgf[towhom=Jill]{tomorrow}
\sayhellopgf[towhom]{today}
\sayhellopgf[towhom=Joe]{tomorrow}
\sayhellopgf[towhom]{tomorrow}
\sayhellopgf{today}
\sayhelloexpl{tomorrow}
\sayhelloexpl[towhom]{today}
\sayhelloexpl[towhom=Jill]{tomorrow}
\sayhelloexpl[towhom]{today}
\sayhelloexpl[towhom=Joe]{tomorrow}
\sayhelloexpl[towhom]{tomorrow}
\sayhelloexpl{today}
\end{document}