Perl 5.30.0。圖書館在今天是最新的。
如果哈希是只讀的,我希望 Scalar::Util::readonly 回傳一些真實值,并且確實如此:
perl -MReadonly -M'Scalar::Util qw(readonly)' -E'
say readonly(%ENV);
Readonly::Hash %ENV => %ENV;
say readonly(%ENV);
'
0
134283264
...除非我還想使用 Types::Standard,然后 Scalar::Util::readonly 不再有效?!
perl -MReadonly -M'Scalar::Util qw(readonly)' -MTypes::Standard -E'
say readonly(%ENV);
Readonly::Hash %ENV => %ENV;
say readonly(%ENV);
'
0
0
我查看了 Types::Standard 的未解決問題,但沒有直接描述我的問題。
這里發生了什么 ?
uj5u.com熱心網友回復:
這不是正確的使用方式readonly。
將哈希傳遞給子是不可能的。只有標量可以作為引數傳遞給 subs。原型可用于使其看起來像您將哈希傳遞給子,但這里不是這種情況。
$ perl -E'
use Scalar::Util qw( readonly );
say prototype( "readonly" ) // "[none]";
'
$
該原型意味著
readonly( %ENV )
方法
&readonly( scalar( %ENV ) )
它不檢查是否%ENV是只讀的;它檢查從在標量背景關系中評估獲得的值是否%ENV是只讀的。這是完全錯誤的。
Scalar::Util::readonly不能用于檢查散列(或陣列)是否為readonly,只能用于檢查標量。
那么如何檢查一個哈希是否是只讀的呢?
好吧,Perl 提供了一個內置的子工程,就像Scalar::Util::readonly被呼叫的一樣Internals::SvREADONLY。與 不同readonly,SvREADONLY在陣列上作為散列和標量作業。
$ perl -E'say prototype( "Internals::SvREADONLY" ) // "[none]";'
\[$%@];$
此原型導致傳遞對第一個引數的參考,而不是引數本身。像這樣,
Internals::SvREADONLY( %x )
簡稱
&Internals::SvREADONLY( \%x )
問題是,回傳的哈希Readonly::Hash實際上并不是只讀的。所以Internals::SvREADONLY沒有比Scalar::Util::readonly.
$ perl -E'
use Readonly qw( );
say Internals::SvREADONLY( %x ) ?1:0;
Readonly::Hash %x => %x;
say Internals::SvREADONLY( %x ) ?1:0;
'
0
0
Readonly::Hash用于tie攔截更改哈希的嘗試。
$ perl -E'
use Devel::Peek qw( Dump );
use Readonly qw( );
Readonly::Hash %x => %x;
Dump( %x );
'
SV = PVHV(0x561f1e51b340) at 0x561f1e5435a8
REFCNT = 1
FLAGS = (RMG,OOK,SHAREKEYS) <--- No READONLY flag.
MAGIC = 0x561f1e558290
MG_VIRTUAL = &PL_vtbl_pack
MG_TYPE = PERL_MAGIC_tied(P) <--- tie() magic was added
MG_FLAGS = 0x02 to intercept attempts
REFCOUNTED to change the hash.
MG_OBJ = 0x561f1e515680
SV = IV(0x561f1e515670) at 0x561f1e515680
REFCNT = 1
FLAGS = (ROK)
RV = 0x561f1e5d39b8
SV = PVHV(0x561f1e51b400) at 0x561f1e5d39b8
REFCNT = 1
FLAGS = (OBJECT,SHAREKEYS)
STASH = 0x561f1e5d3c88 "Readonly::Hash"
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7
AUX_FLAGS = 0
ARRAY = 0x561f1e541950
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
RAND = 0x2685e09f
以下是模塊如何檢查它是否已經將哈希設定為只讀:
tied( %x ) =~ 'Readonly::Hash'
那么為什么使用后輸出的差異Readonly::Hash呢?
雖然這個問題沒有實際意義,但它仍然是一個有趣的問題。
好吧,這是由于Readonly::Hash: 它在標量背景關系中回傳錯誤的值造成的。
$ perl -E'
use Readonly qw( );
my %x = ( a=>4, b=>5, c=>6 );
say scalar( %x );
Readonly::Hash %x => %x;
say scalar( %x );
'
3
1
當%x在標量背景關系中使用時,Perl 回傳散列中元素的數量。[1]
另一方面,添加的魔法Readonly::Hash使它在哈希不為空時回傳一個真值,而在哈希為空時回傳一個假值。
這就是區別所在。
Perl 回傳一個計數作為臨時的又名凡人標量。它被創建為包含回傳的值,并在呼叫者有機會復制它后被釋放。花時間將其設為只讀是沒有意義的。[2]
另一方面,Readonly::Hash 不僅回傳任何真或假標量。它回傳與每個回傳 true 或 false 的 Perl 運算子回傳的完全相同的 true 和 false 標量。不是副本,而是完全相同的標量,&PL_sv_yes并且&PL_sv_no. [3]這些標量是只讀的。[4]
那么為什么 Types::Standard 會起作用呢?
雖然這個問題沒有實際意義,但它仍然是一個有趣的問題。
不幸的是,我還沒有弄清楚那個。
情況并非總是如此。它從不只回傳真/假,但舊值實際上僅作為真/假值有用。
有一些困難,你可以修改它(
my $r = \scalar(%x); $$r),但沒有意義。這樣做不會對哈希產生影響。瑣事:除了 之外
&PL_sv_undef,它們是僅有的三個靜態分配的標量。它們是只讀的,因為我們不想因為意外更改
4 == 5而開始回傳真值。&PL_sv_no
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/475688.html
標籤:perl
上一篇:如何在偶數和奇數之間交替?
