
Почему \setlength
неэффективен внутри tabular
среды? Вот MWE:
\documentclass{article}
\newlength{\globallength}
\newlength{\locallength}
\begin{document}
\setlength{\globallength}{10pt}%
\begin{tabular}{l}
\setlength{\locallength}{10pt}%
\hspace*{10pt}. \\
\hspace*{\globallength}. \\
\hspace*{\locallength}. \\
\hspace*{0pt}. \\
\end{tabular}
\end{document}
В то время как первые две точки хорошо выровнены, третья отличается и ведет себя так, как будто бы \locallength
это были 0pt
. Почему так и что я могу сделать? Я хочу использовать \setwidth
внутри tabular
среды, поэтому установка длины за пределами среды на самом деле не вариант.
решение1
Ячейки выравнивания обрабатываются внутри неявной группы, поэтому локальные назначения переменным отменяются по завершении группы.
Определение ядра \setlength
:
% latex.ltx, line 2181:
\def\setlength#1#2{#1 #2\relax}
вот почему\global\setlength
кажетсяработать. С другой стороны, определение \settowidth
есть
% latex.ltx, line 2187:
\def\settowidth {\@settodim\wd}
и определение \@settodim
есть
% latex.ltx, line 2183:
\def\@settodim#1#2#3{\setbox\@tempboxa\hbox{{#3}}#2#1\@tempboxa
\setbox\@tempboxa\box\voidb@x}
Таким образом \global\settowidth{\locallength}{abc}
, станет
\global\setbox\@tempboxa\hbox{{abc}}\locallength\wd\@tempboxa\setbox\@tempboxa\box\voidb@x
что, конечно, неэффективно при выполнении глобального назначения \locallength
.
Да, \settowidth{\global\locallength}{abc}
это сработало бы, но это просто случайность.
В LaTeX нет поддержки глобальных назначений размерности/пропуска, и вам следует полагаться на команды более низкого уровня. Поэтому более безопасный способ — определить новые команды:
\makeatletter
\newlength\local@length@for@global
\newcommand\gsetlength[2]{%
\setlength{\local@length@for@global}{#2}%
\global#1\local@length@for@global
}
\newcommand{\gsettowidth}[2]{%
\settowidth{\local@length@for@global}{#2}%
\global#1\local@length@for@global
}
\makeatother
и аналогично для \gsettoheight
и \gsettodepth
если необходимо.
Это будет работать, даже если calc
загружено и не использует какую-либо конкретную реализацию «локальных» команд.
решение2
Оба варианта \global\setlength{\locallength}{10pt}
, \setlength{\global\locallength}{10pt}
похоже, работают, но я понятия не имею, зачем это нужно.
https://tex.stackexchange.com/a/210598/30810заставил меня попробовать это, и комментарий @ChristianHupfer объясняет, почему.
В моем более длинном документе \global\settowidth{...}
не сработало; \settowidth{\global...}
сработало.