Измененное определение макроса возвращается к исходному

Измененное определение макроса возвращается к исходному

У меня есть две команды, \testoneи \testtwo. \testtwoпоявляется только если раньше была соответствующая команда \testoneи принимает те же аргументы. Поэтому я хочу \testoneсохранить ее аргументы в \@repeat@meтом месте, где \testtwoона снова их подхватывает, чтобы мне не приходилось вводить их дважды.

Однако это работает только если оба находятся в одной среде. Но в некоторых случаях он решает, что измененное значение \@repeat@meследует игнорировать.

\documentclass{article}
\makeatletter

\def\@repeat@me{}

\newcommand\testtwo{\bf{\@repeat@me}% print what is currently defined.
% reset the definition so it does not interfere with next call
\def\@repeat@me{}}

% print it and then remember it.
\newcommand\testone[1]{\def\@repeat@me{#1}\emph{\@repeat@me}}%

\makeatother
\begin{document}

% prints: \emph{Hello World} \bf{Hello World}
\testone{Hello World} \testtwo{}

% prints: \bf{\emph{Hello World}}
% intended: \bf{\emph{Hello World}} \bf{Hello World}
\bf{\testone{Hello World}} \testtwo{}

\end{document}

решение1

Если вам нужно глобальное назначение (чтобы избежать групп и сред, вам нужно) \global\def(или \gdef):

\documentclass{scrartcl}

\makeatletter
\newcommand*\@repeat@me{}
\newcommand*\testtwo{\textbf{\@repeat@me}\gdef\@repeat@me{}}
\newcommand\testone[1]{\gdef\@repeat@me{#1}\emph{\@repeat@me}}
\makeatother

\begin{document}

\testone{Hello World} \testtwo
\textbf{\testone{Hello World}} \testtwo

\end{document}

решение2

Обратите внимание, что TeX устанавливает область действия, в которой (пере)определения могут существовать и быть отменены за ее пределами. Вот что здесь происходит. Давайте рассмотрим расширения:

\testone{Hello World} \testtwo{}

расширяется до (с комментариями)

\def\@repeat@me{Hello World}\emph{\@repeat@me} % \testone{Hello World}
\textbf{\@repeat@me}\def\@repeat@me{}% \testtwo{}

который расширяется до

\emph{Hello World} \textbf{Hello World}% Using the new definition of \@repeat@me

введите описание изображения здесь

Теперь посмотрим на расширения второго набора макросов:

\textbf{\testone{Hello World}} \testtwo{}

расширяется до (с комментариями)

\textbf{% <--- start of a group/scope
  def\@repeat@me{Hello World}\emph{\@repeat@me}% \testone{Hello World}
} % <--- end of a group/scope
\textbf{\@repeat@me}\def\@repeat@me{}% \testtwo{}

который расширяется до

\textbf{\emph{Hello World}} % At scope-end, \@repeat@me reverts to its original definition
\textbf{}% Since \@repeat@me is empty {}

введите описание изображения здесь

Использование глобального определения, например, \gdefвыводит переопределение \@repeat@meвыживания за рамки, предоставляемые \textbf{..}.


введите описание изображения здесь

\documentclass{article}
\makeatletter

\def\@repeat@me{}

% print it and then remember it.
\newcommand\testone[1]{\gdef\@repeat@me{#1}\emph{\@repeat@me}}%

\newcommand\testtwo{\textbf{\@repeat@me}% print what is currently defined.
  % reset the definition so it does not interfere with next call
  \def\@repeat@me{}}

\makeatother
\begin{document}

% prints: \emph{Hello World} \textbf{Hello World}
\testone{Hello World} \testtwo{}

% prints: \textbf{\emph{Hello World}} \textbf{Hello World}
\textbf{\testone{Hello World}} \testtwo{}

\end{document}

Связанный контент