始まり
Rubyを勉強し始めていて、Rubyで Array.new(5,'default')
などとすると、要素数5の配列が生成されるが、これら1つ1つの要素は同じオブジェクトIDを所持している為 a[0].upcase!
などとすると全ての要素が変更される事を知った。
普段書いているのはPerlなので、Perlではどのようにするとこれが再現できるかを考えてみた。
Perlで一気に同一オブジェクトのリファレンスを持つ配列とか作れるのかな
— 八雲アナグラ (@AnaTofuZ) 2018年2月22日
試みる
id:mackee_w さんに拾っていただき試みが始まる。
map { $obj } 1...10 みたいなことかな
— トーカナイザの守護霊 (@mackee_w) 2018年2月22日
そして書いたコード
#!/usr/bin/env perl use strict; use warnings; use DDP { deparse => 1 }; my $hoge = {hoge => "saru"}; my @hoge = map { $hoge } (1..10); p @hoge;
なるほど pic.twitter.com/VyDr2DsAT7
— 八雲アナグラ (@AnaTofuZ) 2018年2月22日
さらに別の方法が議論される。
まてよ、( $obj x 10 )でもいける気がする
— トーカナイザの守護霊 (@mackee_w) 2018年2月22日
x演算子滅多に使わないからアレかもだけど、例えば()で囲わないといけないとか
— トーカナイザの守護霊 (@mackee_w) 2018年2月22日
$obj x 10 だと文字列解釈?で[0]にリファレンスが10連続で来る形になりました。リスト展開されてる… pic.twitter.com/b6DewKhShi
— 八雲アナグラ (@AnaTofuZ) February 22, 2018
($hoge) x 10;だといけました
— 八雲アナグラ (@AnaTofuZ) 2018年2月22日
リストを10連続っていうコンテキストか
— 八雲アナグラ (@AnaTofuZ) February 22, 2018
— トーカナイザの守護霊 (@mackee_w) 2018年2月22日
そして書かれたコード達
#!/usr/bin/env perl use strict; use warnings; use DDP { deparse => 1 }; my $hoge = {hoge => "saru"}; #my @hoge = map { $hoge } (1..10); # #p @hoge; my @array = ($hoge) x 10; p @array;
use Data::Dumper; my $h = { hoge => "huga" }; warn Dumper [ ($h) x 10 ];
解説
PerlではオブジェクトIDのようなものはリファレンスそのものなので、リファレンスをリストコンテキストでn回増やし配列に代入するとこのような事が可能だった。
mapの例は (1..10)
で範囲を表して同じようなことを行っている。
感想
Perlで考えてみると実際の処理が解ってくる気がした。