使用 \globaldefs 设置全局 pgf 键值对是否安全?

使用 \globaldefs 设置全局 pgf 键值对是否安全?

在这篇文章的帮助下(有没有办法使用“pgfkeys”设置*全局*键值?),我找到了一种更简单的方法来解决我自己的问题(如何在具有表格的自定义环境中使用 pgfkeys 创建使用多个参数的命令?)。我称其为更简单,因为我对 LaTeX 缺乏深入的了解,所以我不理解该帖子中描述的解决方案。

我的解决方案的代码如下:

\documentclass{article}
\usepackage{pgfkeys}

\def\showstatus{%
    (level: \the\currentgrouplevel\ -- 
     globaldefs: \the\globaldefs\ --
     foo: \pgfkeysvalueof{/rpath/tpath/var3} --
     bar: \pgfkeysvalueof{/rpath/tpath/var4})
}

\def\customvarset{\pgfqkeys{/rpath}}

\newenvironment{customenvtab}{%
    \newcommand*{\resetvarsettab}{%
        \customvarset{%
                      tpath/.cd,%
                      var3/.initial=var3 tbd,%
                      var4/.initial=var4 tbd
        }
    }
    \resetvarsettab
    \def\tabval##1{\pgfkeysvalueof{/rpath/tpath/##1}}
    \newcommand{\cmdtab}[1]{%
        \globaldefs=1
        \customvarset{tpath/.cd, ##1}
        \tabval{var3} & \tabval{var4}
        \globaldefs=1
        \resetvarsettab
    }
    \begin{tabular}{c|c}
}{%
    \end{tabular}
}

\begin{document}
\section{Now Working}
%\showstatus
\begin{customenvtab}
\cmdtab{}\\
\cmdtab{var3=test var3}\\
\cmdtab{var4=test var4}\\
\cmdtab{var3=blo, var4=bli}
\end{customenvtab}
%\showstatus

\end{document}

使用 \globaldefs=1 的自己的解决方案

现在的问题是:出于这个目的使用 \globaldefs=1 是否危险?如果是,我需要注意什么?或者我根本不应该使用它?

预先感谢您的帮助!

答案1

正如 David Carlisle 在其评论中指出的那样:

“除非您已经审查了其范围内的每一行代码,并且您亲自维护该代码,否则在任何地方使用它都是不安全的\globaldefs,这样您就可以确保更改不会使全局定义无效。”

因此,让我们集中精力寻找另一种方法:

您似乎希望通过设置来解决的问题\globaldefs是设置键仅限于当前表单元格。

较新的 TeX 引擎带来了可扩展原语\expanded。这可能会引起你的兴趣,因此你可能不需要修改\globaldefs:

\documentclass{article}
\usepackage{pgfkeys}

\newcommand*\showstatus{%
    (level: \the\currentgrouplevel\ -- 
     globaldefs: \the\globaldefs\ --
     foo: \pgfkeysvalueof{/rpath/tpath/var3} --
     bar: \pgfkeysvalueof{/rpath/tpath/var4})%
}

\newcommand*\customvarset{\pgfqkeys{/rpath}}

\newenvironment{customenvtab}{%
    \newcommand*\resetvarsettab{%
        \customvarset{%
                      tpath/.cd,%
                      var3/.initial=var3 tbd,%
                      var4/.initial=var4 tbd
        }%
    }%
    \resetvarsettab
    \newcommand*\tabval[1]{\pgfkeysvalueof{/rpath/tpath/##1}}%
    \newcommand\cmdtab[1]{%
        \customvarset{tpath/.cd, ##1}%
        {\let\protect\noexpand\expandafter}%
        \expandafter\resetvarsettab
        \expanded{bold value: \textbf{\tabval{var3}} & italic value: \textit{\tabval{var4}}}%
    }%
    \begin{tabular}{c|c}%
}{%
    \end{tabular}%
}

\begin{document}
\section{Now Working}
%\showstatus
\begin{customenvtab}
\cmdtab{}\\
\cmdtab{var3=test var3}\\
\cmdtab{var4=test var4}\\
\cmdtab{var3=blo, var4=bli}
\end{customenvtab}
%\showstatus
\end{document}

使用 \expanded 自己的解决方案



如果您希望进行细粒度的扩展控制,请注意\tabval需要四个扩展步骤才能提供结果:

步骤 1 传递\pgfkeysvalueof
步骤 2 传递\csname...\endcsname
步骤 3 传递控制序列标记。
步骤 4 传递控制序列标记的顶层扩展。


四个扩展步骤依次意味着 2 4 -1=15 \expandafter...

如果你不熟悉\expandafter扩展技巧,你可能会对这个问题感兴趣如何知道附加到 csname 宏时的 expandafter 数量?及其答案。

\expandafter影响下一个和下一个标记:
的顶层扩展是下一个\expandafter标记\expandafter

  • 如果下一个标记是可扩展的:下一个标记的顶层扩展。
  • 如果下一个 - 倒数一个标记不可扩展:则下一个 - 倒数一个标记。

\documentclass{article}
\usepackage{pgfkeys}

\newcommand*\showstatus{%
    (level: \the\currentgrouplevel\ -- 
     globaldefs: \the\globaldefs\ --
     foo: \pgfkeysvalueof{/rpath/tpath/var3} --
     bar: \pgfkeysvalueof{/rpath/tpath/var4})%
}

\newcommand*\customvarset{\pgfqkeys{/rpath}}

\chardef\stopromannumeral=`\^^00
\newcommand\exchange[2]{#2#1}
\newcommand\passfirsttosecond[2]{#2{#1}}
\newcommand\obtaintabvalandexchange[3]{%
  % #1 <tokens to prepend to brace-nested value of pgf-"variable">
  % #2 pgf-"variable"
  % #3 <stuff to prepend>
  % yields
  % <stuff to prepend><tokens to prepend to brace-nested value of pgf-"variable">{<value of pgf-"variable">}
  \expandafter\exchange\expandafter{\romannumeral
     \expandafter\passfirsttosecond\expandafter{%
       \romannumeral
       \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
       \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
       \expandafter\stopromannumeral
       \tabval{#2}%
     }{\stopromannumeral#1}%
  }{#3}%
}%
\newenvironment{customenvtab}{%
    \newcommand*\resetvarsettab{%
        \customvarset{%
                      tpath/.cd,%
                      var3/.initial=var3 tbd,%
                      var4/.initial=var4 tbd
        }%
    }%
    \resetvarsettab
    \newcommand*\tabval[1]{\pgfkeysvalueof{/rpath/tpath/##1}}%
    \newcommand\cmdtab[1]{%
        \customvarset{tpath/.cd, ##1}%
        \obtaintabvalandexchange{italic value: \textit}{var4}{%
           % You can nest \obtaintabvalandexchange in
           % \obtaintabvalandexchange's 3rd argument.
           % The last nesting-level then denotes the value in the
           % leftmost table-cell.
           \obtaintabvalandexchange{bold value: \textbf}{var3}{\resetvarsettab} & 
        }%
    }%
    \begin{tabular}{c|c}%
}{%
    \end{tabular}%
}

\begin{document}
\section{Now Working}
%\showstatus
\begin{customenvtab}
\cmdtab{}\\
\cmdtab{var3=test var3}\\
\cmdtab{var4=test var4}\\
\cmdtab{var3=blo, var4=bli}
\end{customenvtab}
%\showstatus
\end{document}

在此处输入图片描述

相关内容