自動活性化

Perlプログラミング言語における自動活性化とは、未定義値が参照されるたびに、必要に応じて新しい配列ハッシュを自動的に作成することです。Perlの自動活性化により、プログラマーは構造化変数とその任意のサブ要素を参照することができ、変数の存在とその完全な構造を事前に明示的に宣言する必要はありません。[ 1 ]

対照的に、他のプログラミング言語では次のいずれかになります。

  1. プログラマーが変数構造の一部を使用または参照する前に、変数構造全体を明示的に宣言することを要求する。
  2. プログラマーが変数構造の一部を参照する前に、その一部について宣言することを要求する。
  3. 変数の一部を参照したり、割り当てたり、その一部を参照する式を作成したりする前に、変数の一部への割り当てを作成します。

Perlの自動活性化は、 PythonPHPRuby、そして多くのCスタイル言語などの言語とは対照的です。これらの言語では、null値や未定義値の参照は一般的に許可されていません。 [ a ]これは、HTML標準の「ウィンドウオブジェクトへの名前付きアクセス」[ 2 ]と比較することができ、対応するグローバルスコープの変数がブラウザベースのJavaScriptから自動的にアクセスできるようになります。

ハッシュ

自動有効化は未定義値が参照解除されたときに発生することを覚えておくことが重要です。代入は不要です。以下のデバッガセッションは、ハッシュを検査するだけで自動有効化が行われる様子を示しています。

DB <1> x \ %h 0 HASH ( 0x2f1a248 )空のハッシュDB <2> x $h { 1 }{ 2 }{ 3 }{ 4 } 0 undef DB <3> x \ %h 0 HASH ( 0x2f1a248 ) 1 => HASH ( 0x2f1a260 ) 2 => HASH ( 0x29a3c68 ) 3 => HASH ( 0x2dc3038 )空のハッシュDB <4>

以下のデバッガー セッションは、内部ハッシュへの割り当てによるハッシュの自動有効化を示しています。

DB <1> $h { A }{ B }{ C }{ D } = 1 DB <2> x \ %h 0ハッシュ( 0x83c71ac ) 'A' =>ハッシュ( 0x837d50c ) 'B' =>ハッシュ( 0x83c71e8 ) 'C' =>ハッシュ( 0x83c7218 ) 'D' => 1 DB <3>

ハッシュは、宣言なしで複数階層に自動的に作成されます。自動活性化は、過剰な型付けを防ぐことができます。Perlが自動活性化をサポートしていなかった場合、上記の構造は次のように作成する必要がありました。

DB <1> %h = ( A => { B => { C => { D => 1 }}}) DB <2> x \ %h 0ハッシュ( 0x83caba4 ) 'A' =>ハッシュ( 0x83cfc28 ) 'B' =>ハッシュ( 0x83cab74 ) 'C' =>ハッシュ( 0x83b6110 ) 'D' => 1 DB <3>

ファイルとディレクトリのハンドル

Perl 5.6.1以降では、ファイルハンドルとディレクトリハンドルの自動有効化をサポートしています。[ 3 ]未定義の変数open()を呼び出すと、その変数はファイルハンドルに設定されます。perl561deltaによると、「これにより、次の例のように、ファイルハンドルを渡す必要がある場合に 型グロブを使用する必要性が大幅に軽減されます。」

for my $file ( qw(this.conf that.conf) ) { my $fin = open_or_throw ( '<' , $file ); process_conf ( $fin ); # close() は必要ありません} use Carp ; sub open_or_throw { my ( $mode , $filename ) = @_ ; open my $h , $mode , $filenameまたはcroak "'$filename' を開けませんでした: $!" ; return $h ; }

他のプログラミング言語でのエミュレーション

C++

C ++標準ライブラリの連想コンテナ(std::unordered_mapおよびstd::map)は、operator[]キーに関連付けられた値を取得するために使用します。このキーに関連付けられた値がない場合、キーを構築し、値を初期化します 。 [ 4 ] intやfloatのような単純な型の場合、値の初期化はゼロ初期化となります。

std :: unordered_map < std :: string , std :: vector < int >> a ; a [ "the answer" ]. push_back ( 42 ); // a["the answer"] ベクトルを自動有効化し、それに追加します。

文字列の出現回数をカウントする別の例:

std :: unordered_map < std :: string , int > counts ; while ( auto & s = GetNextString ()) { counts [ s ] ++ ; // counts[s] が存在しない場合は作成し、ゼロに設定してから増分します。}

同様のトリックは、キーに関連付けられた要素が既に存在する場合でも、その要素への 反復子insert()を返す メソッドでも実現できます。

パイソン

Pythonの組み込みクラスは、Python v2.5でクラスに追加されたメソッドをオーバーライドするだけで、自動生成辞書を実装するようにサブクラス化dictできます。 [ 5 ]この動作を実装する方法は他にもありますが、[ 6 ] [ 7 ]以下は最も単純な方法の1つであり、クラスのインスタンスは通常のPython辞書オブジェクトと同じように印刷されます。 __missing__()

>>>クラスTree ( dict ): ... def __missing__ ( self , key ): ... value = self [ key ] = type ( self )() ...戻り>>> # 綱、目、属、タイプ種による一般名>>> common_names = Tree () >>> common_names [ 'Mammalia' ][ 'Primates' ][ 'Homo' ][ 'H. sapiens' ] = 'human being' >>> common_names {'Mammalia': {'Primates': {'Homo': {'H. sapiens': 'human being'}}}}>>> # 演劇、幕、シーン、ページ別の有名な引用>>> quotes = Tree () >>> quotes [ 'ハムレット' ][ 1 ][ 3 ][ 3 ] = '何よりもこれ: 汝自身の心に忠実であれ。' >>> quotes {'ハムレット': {1: {3: {3: '何よりもこれ: 汝自身の心に忠実であれ。'}}}}

ルビー

Rubyのハッシュは、存在しないインデックスに対して返されるオブジェクトを指定するブロックを受け取ることができます。これは自動生成マップの実装に使用できます。

irb(main):001:0> tree = proc { Hash . new { | hash , key | hash [ key ] = tree . call } } => #<Proc:0x007fda528749a0@(irb):1> irb(main):002:0> lupin = tree . call => {} irb(main):003:0> lupin [ "express" ][ 3 ] = "stand and deliver" => "stand and deliver" irb(main):004:0> lupin => {"express"=>{3=>"stand and deliver"}}

ジャワ

Java Mapには自動生成マップをエミュレートできる メソッドcomputeIfAbsent[ 8 ]がある。

パブリック静的< K , V > Function < K , V > defaultDict ( Map < K , V > map Supplier <? extends V > supplier ) { return key -> map . computeIfAbsent ( key k -> supplier . get ()); }public static void main ( String [] args ) { Function < String , List < String >> dict = defaultDict ( new HashMap <> (), ArrayList :: new ); dict . apply ( "foo" ). add ( "bar" ); }

PHP

PHP 配列はネイティブで自動有効化されます。

$arr = array (); $arr [ "express" ][ 3 ] = "stand and deliver" ;

ただし、これは割り当てにのみ適用され、配列アクセスには適用されません。

JavaScript

ES6では、自動有効化を実装できる 新しいProxyクラスが導入されました。JavaScriptの他の機能と組み合わせることで、この処理は1行のコードに短縮できます。

var tree = () => new Proxy ({}, { get : ( target name ) => name in target ? target [ name ] : target [ name ] = tree () });// テスト: var t = tree (); t . first . second . third = 'text' ; console . log ( t . first . second . third ); // または t['first']['second']['third']

C#

C#、インデクサーとC# 4.0ダイナミクスを使用

クラスTree { private IDictionary <文字列オブジェクト> _dict = new Dictionary <文字列オブジェクト> ();public dynamic this [ string key ] { get { return _dict . ContainsKey ( key ) ? _dict [ key ] : _dict [ key ] = new Tree (); } set { _dict [ key ] = value ; } } }//テスト: var t = new Tree (); t [ " first" ][ "second" ][ "third" ] = "text" ; Console.WriteLine ( t [ "first" ][ "second" ][ "third" ]);

DynamicObject異なる構文を実装するためにも使用できます。

Systemを使用します。System.Collections.Generic使用します。System.Dynamic使用しますクラスTree : DynamicObject { private IDictionary <オブジェクトオブジェクト> dict = new Dictionary <オブジェクトオブジェクト> ();// t.first.second.third 構文public override bool TryGetMember ( GetMemberBinder binder , out object result ) { var key = binder . Name ;if ( dict . ContainsKey ( key ))結果= dict [ key ]; else dict [ key ] =結果= new Tree ();trueを返します; } public override bool TrySetMember ( SetMemberBinderバインダーオブジェクト) { dict [バインダー. Name ] =; trueを返します; }// t["first"]["second"]["third"] の場合 構文public override bool TryGetIndex ( GetIndexBinder binder object [] indexes out object result ) { var key = indexes [ 0 ];if ( dict . ContainsKey ( key ))結果= dict [ key ]; else dict [ key ] =結果= new Tree ();trueを返します; }public override bool TrySetIndex ( SetIndexBinderバインダーオブジェクト[]インデックスオブジェクト) { dict [インデックス[ 0 ]] =; trueを返します; } }// テスト: dynamic t = new Tree (); t . first . second . third = "text" ; Console . WriteLine ( t . first . second . third );// または、動的t = new Tree (); t [ " first" ][ "second" ][ "third" ] = "text" ; Console.WriteLine ( t [ "first" ][ "second" ][ "third" ]) ;

参照

注記

  1. ^例えば、Python では None.__getitem__ が呼び出されると TypeError が発生します。Cnullポインターを逆参照すると未定義の動作が発生します。そのため、多くの C 実装ではセグメンテーション違反が発生するようになっています。

参考文献

  1. ^シュワルツ、ランダル・L.、フェニックス、トム (2003). 『Perlオブジェクトの学習 O'Reilly Media, Inc. p.  42. ISBN 9780596004781このプロセスは自動有効化と呼ばれます。存在しない変数、または変数の位置(技術的には左辺値コンテキストと呼ばれます)を探す際に参照解除されるundefを含む変数には、自動的に適切な空項目への参照が詰め込まれます…
  2. ^ 「HTML 標準。Window オブジェクトへの名前付きアクセス」
  3. ^ "perl561delta - perl v5.6.1の新機能" . Perlプログラミングドキュメント.
  4. ^「値の初期化」、C++リファレンス(wiki)
  5. ^ 「マッピング型 — dict」 。 2016年6月13日閲覧
  6. ^ 「Pythonでネストされた辞書を実装する最良の方法は何ですか?」2016年6月13日閲覧
  7. ^ 「Pythonの1行ツリー」 。 2017年12月27日閲覧
  8. ^ 「Map (Java Platform SE 8)」 . 2015年5月17日閲覧