Por que \setlength é ineficaz dentro de um ambiente tabular?

Por que \setlength é ineficaz dentro de um ambiente tabular?

Por que é \setlengthineficaz dentro de um tabularambiente? Aqui está um 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}

Enquanto os dois primeiros pontos estão bem alinhados, o terceiro é diferente e se comporta como se \locallengthestivesse 0pt. Por que isso acontece e o que posso fazer? Quero usar \setwidthdentro do tabularambiente, então definir o comprimento fora do ambiente não é realmente uma opção.

Responder1

As células de alinhamento são processadas dentro de um grupo implícito, portanto as atribuições locais às variáveis ​​são desfeitas quando o grupo termina.

A definição do kernel \setlengthé

% latex.ltx, line 2181:
\def\setlength#1#2{#1 #2\relax}

e é por isso\global\setlength parecetrabalhar. Por outro lado, a definição de \settowidthé

% latex.ltx, line 2187:
\def\settowidth {\@settodim\wd}

e a definição de \@settodimé

% latex.ltx, line 2183:
\def\@settodim#1#2#3{\setbox\@tempboxa\hbox{{#3}}#2#1\@tempboxa
       \setbox\@tempboxa\box\voidb@x}

Assim \global\settowidth{\locallength}{abc}se tornaria

\global\setbox\@tempboxa\hbox{{abc}}\locallength\wd\@tempboxa\setbox\@tempboxa\box\voidb@x

o que, obviamente, é ineficaz para fazer uma atribuição global para \locallength.

Sim, \settowidth{\global\locallength}{abc}funcionaria, mas é apenas por acaso.

Não há suporte no LaTeX para atribuições de dimensão/pular global e você deve confiar em comandos de nível inferior. Então uma maneira mais segura é definir novos comandos:

\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

e da mesma forma para \gsettoheighte \gsettodepthse necessário.

Isso funcionará mesmo se calcestiver carregado e não explorar nenhuma implementação específica dos comandos “locais”.

Responder2

Ambos \global\setlength{\locallength}{10pt}e \setlength{\global\locallength}{10pt}parecem funcionar, mas não tenho ideia de por que isso seria necessário.

https://tex.stackexchange.com/a/210598/30810me fez tentar, e o comentário de @ChristianHupfer explica o porquê.

No meu documento mais longo, \global\settowidth{...}não funcionou; \settowidth{\global...}fez.

informação relacionada