20 使用l3keys如何不能实现单独指定某个option?

发布于 2024-10-30 22:56:54

总的目标:希望使用l3keys实现如下的效果。

image.png

CASE A
下面这段代码,无法实现指定opa已经opb并赋值到对应宏的操作。
应该如何修改?

\documentclass{article}
\usepackage[margin=1in]{geometry}
\setlength{\parindent}{0pt}
\ExplSyntaxOn
    \keys_define:nn{mwe}
    {
        %opa.code:n = {The~Optional~Parameter~A~is~#1~\par},
        %opa.default:n = {defaulta},
        opa .tl_set:N = \l_mwe_opa_tl,
        %opb.code:n = {The~Optional~Parameter~B~is~#1~\par},
        %opb.default:n = {defaultb},
        opb .tl_set:N = \l_mwe_opb_tl,
    }
    \keys_set:nn{mwe}{
        opa = defaulta,
        opb = defaultb,
    }
    \NewDocumentCommand{\cmd}{ o m }{
        \IfNoValueF{#1}{
            \keys_set:nn{mwe}{#1}
            }
        The~Optional~Parameter~A~is~{\tl_use:N \l_mwe_opa_tl}.~\par
        The~Optional~Parameter~B~is~{\tl_use:N \l_mwe_opb_tl}.~\par
        The~Mandatory~Parameter~is~{#2}.~\par
    }
\ExplSyntaxOff
\begin{document}
\cmd{Explorer}

\cmd[opa=opa,opb=opb]{Explorer}

\cmd[opa=opa]{Explorer}

\cmd[opb=opb]{Explorer}

\end{document}

image.png

CASE B
另外一个问题是,如果使用<key>.code:n以及<key>.default:n来实现的话,似乎会出现如果不显式指定参数则不会被赋值的情况,想知道这两种基于l_tmp_tl以及基于.code:n.default:n进行初始化的区别和正确的操作方式?
如下面的MWE:

\documentclass{article}
\usepackage[margin=1in]{geometry}
\setlength{\parindent}{0pt}

\begin{document}
\ExplSyntaxOn
    \keys_define:nn{mwe}
    {
        opa.code:n = {The~Optional~Parameter~A~is~#1~\par},
        opa.default:n = {defaulta},
        opb.code:n = {The~Optional~Parameter~B~is~#1~\par},
        opb.default:n = {defaultb},
    }
    \NewDocumentCommand{\cmd}{ o m }{
        \IfNoValueF{#1}{
            \keys_set:nn{mwe}{#1}
        }
        The~Mandatory~Parameter~is~{#2}~\par
    }
\ExplSyntaxOff
\cmd{Explorer}

\cmd[opa=opa,opb=opb]{Explorer}

\cmd[opa=opa]{Explorer}

\cmd[opb=opb]{Explorer}

\end{document}

image.png

查看更多

关注者
0
被浏览
315
雾月
雾月 2024-10-31
这家伙很懒,什么也没写!

猜你想要 lttemplates(即 xtemplate),即将进入 LaTeX2e 内核(不出意外的话是 Released 2024-11-01),目前(2024.10.31)可以使用 xelatex-dev 等 dev 版。

l3keys(包括其它键值宏包)都不会每次没给出键时自动使用默认值,只会使用初始值,但 lttemplates 会。

2 个回答
Sagittarius Rover
Sagittarius Rover 2024-10-31
我要成为TikZ糕手/(ㄒoㄒ)/~~

按照惯例自答一下,非常感谢@Eureka 和@u19850 的倾情帮助。

首先分析下错因:
对于CASEA的写法,是使用自行在外部使用\keys_set:nn {<module>}{options}的方式定义默认值,实际上这等价于在\keys_define:nn内部使用<key>.initial定义其赋值方式,这两种做法均会给option赋值初始值;
对于CASEB的写法,是使用<key>.code:n会接受名为#1的由<key>.default定义的初始值<value>,并执行code的内容;但<key>.default:n方法定义的default值仅仅是在value缺失时的默认值,如果option不被指定是不会被赋值的。

下面附interface3中对这两个函数的介绍原文:

⟨key⟩ .default:n = {⟨default⟩}
Creates a ⟨default⟩ value for ⟨key⟩, which is used if no value is given. This will be used if only the key name is given, but not if a blank ⟨value⟩ is given.

key .default:n = xxx, 是 value 缺失时的默认值
例如 key .default:n = xxx,那么\keys_set:nn {mew}{key} 等价于\keys_set:nn {mew}{key = xxx}

⟨key⟩ .initial:n = {⟨value⟩}
Initialises the ⟨key⟩ with the ⟨value⟩, equivalent to \keys_set:nn {⟨module⟩} { ⟨key⟩ = ⟨value⟩ }

key .initial:n = xxx, 等价于执行了 \keys_set:nn{mwe}{key = xxx}

鱼老师随便一句话就是标准的文档啊,无敌了!

作为一名learner,自然要分析下为什么上面的代码都不得行:

对于CASEA

  • 第28行的\cmd{Explorer}输出了\l_mwe_opa_tl以及\l_mwe_opb_tl的默认值,因此首先输出了正常的结果。
  • 第29行的\cmd[opa=opa,opb=opb]{Explorer}进入了\IfNoValueF的条件逻辑中,此时(\l_mwe_opa_tl,\l_mwe_opb_tl)=(opa,opb),同时正常输出(opa,opb,Explorer)的内容
  • 第30行的\cmd[opa=opa]只是制定了赋值\l_mwe_opa_tl=opa,但由于\l_mwe_opa_tl在上一个判断中已经被永久地赋值为了opb,因此后文中并未将其恢复为defaultb.(第31行同理)

此时已经不难发现是一个变量作用域的问题,可以在自定义的命令\cmd内使用\begin_group:以及\end_group:。事实上鱼老师再次一阵见血地指出:

"这种一般都要加group限制"

对于CASEA,此时只要加上限制,则可以解决上述问题。
image.png

而对于CASEB,可以如上分析:

  • 第21行的\cmd{Explorer}没有指定opaopb,因此 此时default值不会被赋值给key,code的内容也不会输出,因此只输出了必须参数Explorer
  • 第22行制定了opa=opa,opb=opb,default值赋值之后被用于的opa=opa覆盖,因此输出了(opa,opb,Explorer)
  • 第23行指定了opa=opa,此时opa经历了先被赋值为defaulta之后被用户选项覆盖为opa,而opb并未被invoked,因此只输出了(opa,Explorer);第24行同理只输出了(opb,Explorer).

更改方式类似,加上group后,用指定option而不赋值的方式调用,如下图:
image.png

暂时的最后(其实还要测试下雾月给出的lttemplates方法),最后一下Eureka老师给出的一段代码(结合了CASEA与CASEB的做法):

image.png

本来还想分析的,凡是如果你有耐心看完上面一大段的话,是显然可以实现要求的。

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览