sub void(&) { $_[0]->(); () }
say context();
say scalar context();
say void { context() };
より高度なコードにより、より優れた構文が得られます。
use syntax qw( void );
say context();
say scalar context();
say void context();
余談ですが、以下はscalar、コンパイル時のディレクティブほど関数ではないことを示しています。
$ diff -u0 \
<( perl -MO=Concise,-exec -Msyntax=void -E'say f()' 2>&1 ) \
<( perl -MO=Concise,-exec -Msyntax=void -E'say scalar f()' 2>&1 )
--- /dev/fd/63 2014-08-17 12:34:29.124827443 -0700
+++ /dev/fd/62 2014-08-17 12:34:29.128827401 -0700
@@ -7 +7 @@
-6 <1> entersub[t6] lKS/TARG <-- "l" for list context
+6 <1> entersub[t7] sKS/TARG <-- "s" for scalar context
同じことがuse syntax qw( void )'sにも当てはまりvoidます:
$ diff -u0 \
<( perl -MO=Concise,-exec -Msyntax=void -E'say f()' 2>&1 ) \
<( perl -MO=Concise,-exec -Msyntax=void -E'say void f()' 2>&1 )
--- /dev/fd/63 2014-08-17 12:34:41.952692723 -0700
+++ /dev/fd/62 2014-08-17 12:34:41.952692723 -0700
@@ -7 +7 @@
-6 <1> entersub[t6] lKS/TARG <-- "l" for list context
+6 <1> entersub[t6] vKS/TARG <-- "v" for void context
仕組みuse syntax qw( void );_
実際の作業はSyntax::Feature::VoidVoid.xsによって行われ、その主要な行は次のとおりです。
STATIC OP* parse_void(pTHX_ GV* namegv, SV* psobj, U32* flagsp) {
return op_contextualize(parse_termexpr(0), G_VOID);
}
STATIC OP* ck_void(pTHX_ OP* o, GV* namegv, SV* ckobj) {
return remove_sub_call(o);
}
BOOT: {
const char voidname[] = "Syntax::Feature::Void::void";
CV* const voidcv = get_cvn_flags(voidname, sizeof(voidname)-1, GV_ADD);
cv_set_call_parser(voidcv, parse_void, &PL_sv_undef);
cv_set_call_checker(voidcv, ck_void, &PL_sv_undef);
}
voidを使用して sub を宣言しget_cvnます。(サブルーチンが定義されることはありません。) のコードはVoid.pm、サブルーチンを呼び出し元のレキシカル スコープにエクスポートします。
voidを使用してユーザー定義の構文に従うように呼び出すことを Perl に伝えますcv_set_call_parser。
voidを使用してコンパイルした後、呼び出しを操作する必要があることを Perl に伝えますcv_set_call_checker。
Perl が の呼び出しに遭遇するとvoid、ユーザー定義パーサーは用語 using を抽出し、用語parse_termexprのコンテキストを using に変更しvoidますop_contextualize。
その後、チェッカーはvoid引数 (項) を残しながら、オペコード ツリーから呼び出しを削除します。