![pgf 中的局部变量与全局变量,与 foreach 的交互](https://linux22.com/image/426596/pgf%20%E4%B8%AD%E7%9A%84%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E4%B8%8E%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%EF%BC%8C%E4%B8%8E%20foreach%20%E7%9A%84%E4%BA%A4%E4%BA%92.png)
我正在尝试编写一个具有可变输入数量的宏(这对我很重要),该宏应返回不同输入的最大长度。它使用foreach
以下宏pgffor
:
\documentclass{article}
\usepackage{pgffor}
%\usepackage{pgfpages}
\newcommand{\getmaxlength}[1]{%
\newlength{\Lmax}
\newlength{\Lcurr}
\setlength{\Lmax}{0pt}
\foreach \arg in {#1} {%
Previous max: \the\Lmax\par
\settowidth{\Lcurr}{\arg}
\ifdim \Lcurr>\Lmax \global\setlength{\Lmax}{\Lcurr} \fi
\arg\ is of length \the\Lcurr\par
New max: \the\Lmax\par
}
}
\begin{document}
\getmaxlength{A,AAA,AA}
\end{document}
在这个玩具示例中,其效果符合预期:
Previous max: 0.0pt
A is of length 7.50002pt
New max: 7.50002pt
Previous max: 7.50002pt
AAA is of length 22.50005pt
New max: 22.50005pt
Previous max: 22.50005pt
AA is of length 15.00003pt
New max: 22.50005pt
但是,这个解决方案既不干净,也不强大:
- 它需要在第 13 行进行
global
分配。我通过反复试验发现了这一点,但我认为它并不干净,而且我不知道副作用。 - 如果我取消注释第 4 行,宏就会崩溃
\usepackage(pgfpages)
,这进一步表明它可能做错了什么。
在任一情况下(删除global
关键字,使用包pgfpages
),我都会获得一种行为,其中 Lmax 在每次循环重复时重置:
Previous max: 0.0pt
A is of length 7.50002pt
New max: 7.50002pt
Previous max: 0.0pt
AAA is of length 22.50005pt
New max: 22.50005pt
Previous max: 0.0pt
AA is of length 15.00003pt
New max: 15.00003pt
我认为这与处理局部变量和全局变量的方式有关foreach
,而一个潜在的解决方案在于使用其remember
选项(看这里)。但是我无法让它工作。(还要记住,Lmax 不是一个“经典”变量,而是一个长度多变的)。
那么,使我的代码能够有效解决这些问题的最简洁的方法是什么?
(顺便说一下,用例如下:我正在尝试为投影仪方程式构建一个“本地叠加”命令(例如,在方程式中将 x(x + 1)更改为 x^2 + x),该命令将遵循所有叠加的固定宽度,以便更加清晰可见。)
答案1
\global\setlength
失败的原因pdfpages
如下
- 此包加载
calc
; - 如果
calc
没有加载,\global\setlength
则会意外运行。
我建议采用不同的方法,避免全局设置。宏\getmaxlength
有一个可选参数,它应该是包装结果维度的东西,默认情况下只显示值。
\documentclass{article}
\ExplSyntaxOn
%% define a command with
%% 1. optional argument #1 and default value \dim_eval:n
%% 2. mandatory argument #2 (which should be a comma separated list
%% The command just transfer the action to the internal function
\NewDocumentCommand{\getmaxlength}{ O{\dim_eval:n} m }
{
\howier_getmaxlength:nn { #1 } { #2 }
}
%% allocate variables of type dimension and box
\dim_new:N \l_howier_getmaxlength_max_dim
\box_new:N \l__howier_getmaxlength_temp_box
%% the main function
\cs_new_protected:Nn \howier_getmaxlength:nn
{
% set the value to zero to start
\dim_zero:N \l_howier_getmaxlength_max_dim
% map over the list given as second argument, using one item at a time
\clist_map_function:nN { #2 } \__howier_getmaxlength_do:n
% use the final value (by default #1 would be \dim_eval:n)
#1 { \l_howier_getmaxlength_max_dim }
}
%% the auxiliary function taking as argument each item in the list
\cs_new_protected:Nn \__howier_getmaxlength_do:n
{
% store the current list item in a box so we can access to its width
\hbox_set:Nn \l__howier_getmaxlength_temp_box { #1 }
% set the dimension variable to the maximum between the previous
% value and the width of the current item
\dim_set:Nn \l_howier_getmaxlength_max_dim
{
\dim_max:nn { \l_howier_getmaxlength_max_dim } { \box_wd:N \l__howier_getmaxlength_temp_box }
}
}
\ExplSyntaxOff
\begin{document}
\getmaxlength{A,AAA,AA}
XAAAX
X\getmaxlength[\hspace]{A,AAA,AA}X
AAAX
\getmaxlength[\hspace*]{A,AAA,AA}X
\end{document}
注意:如果你运行的是 2020-10-01 版本之前的 LaTeX,你需要
\usepackage{xparse}