Perlの「my」と「our」の違いは何ですか?


188

myPerlには何があるか知っています。変数が定義されているブロックのスコープ内にのみ存在する変数を定義します。何をしourますか?

どうour違うのmy

回答:


215

すばらしい質問:とはどのようにour違いmy、何をしourますか?

要約すれば:

Perl 5以降で利用可能であり、my非パッケージ変数を宣言する方法です。

  • 民間
  • 新着
  • 非グローバル
  • どのパッケージからも分離されるため、変数の形式でアクセスできません$package_name::variable


一方、our変数はパッケージ変数であるため、自動的に次のようになります。

  • グローバル変数
  • 間違いなくプライベートではない
  • 必ずしも新しいとは限らない
  • できるように、修飾された名前空間とパッケージ(または字句範囲)の外にアクセスします$package_name::variable


で変数を宣言すると、入力ミスの警告やコンパイル時のエラーが発生することなく、変数ourを事前に宣言して使用できますuse strict。Perl 5.6以降、use varsファイルスコープのみであり、レキシカルスコープのままではない、廃止されたを置き換えましたour

たとえば、$x内部の変数の正式な修飾名package main$main::xです。宣言をour $x使用すると$x、スクリプトがuse strictまたはを使用するときに、宣言のスコープ内でペナルティなし(つまり、エラーが発生しない)の裸の変数を使用できますuse strict "vars"。スコープは、1つ、2つ、またはそれ以上のパッケージ、または1つの小さなブロックです。


2
では、私たちと地元の人々との違いは何ですか?
Nathan Fellman、

17
@Nathan Fellman、local変数を作成しません。それはに関連していないmyour、すべてで。local変数の値を一時的にバックアップし、現在の値をクリアします。
池上

1
our変数はパッケージ変数ではありません。それらはグローバルスコープではありませんが、レキシカルスコープ変数は変数と同じmyです。次のプログラムで確認できますpackage Foo; our $x = 123; package Bar; say $x;。パッケージ変数を「宣言」する場合は、を使用する必要がありますuse vars qw( $x );。がコンパイルさour $x;れたパッケージ内の同じ名前の変数にエイリアスされるレキシカルスコープの変数を宣言しますour
池上2016年

60

cartmanとOlafurからのPerlMonksとPerlDocのリンクは、優れたリファレンスです。以下は、私の要約です。

my変数は{}{}sにない場合、同じファイルによって定義された単一のブロック内または同じファイル内でレキシカルにスコープされます。同じ字句スコープ/ブロックの外部で定義されたパッケージ/サブルーチンからはアクセスできません。

our変数のスコープはパッケージ/ファイル内にあり、そのパッケージまたはファイルuseまたはコードからアクセスできrequireます。名前の競合は、適切な名前空間を付加することによりパッケージ間で解決されます。

まとめると、local変数は「動的に」スコープさmyれ、同じブロック内で呼び出されたサブルーチンからもアクセスできるという点で変数とは異なります。


my変数内の+1 は、{}sにない場合、同じファイル内でレキシカルスコープ[...] です。」それは私にとって役に立ちました、ありがとう。
Georg

48

例:

use strict;

for (1 .. 2){
    # Both variables are lexically scoped to the block.
    our ($o);  # Belongs to 'main' package.
    my  ($m);  # Does not belong to a package.

    # The variables differ with respect to newness.
    $o ++;
    $m ++;
    print __PACKAGE__, " >> o=$o m=$m\n";  # $m is always 1.

    # The package has changed, but we still have direct,
    # unqualified access to both variables, because the
    # lexical scope has not changed.
    package Fubb;
    print __PACKAGE__, " >> o=$o m=$m\n";
}

# The our() and my() variables differ with respect to privacy.
# We can still access the variable declared with our(), provided
# that we fully qualify its name, but the variable declared
# with my() is unavailable.
print __PACKAGE__, " >> main::o=$main::o\n";  # 2
print __PACKAGE__, " >> main::m=$main::m\n";  # Undefined.

# Attempts to access the variables directly won't compile.
# print __PACKAGE__, " >> o=$o\n";
# print __PACKAGE__, " >> m=$m\n";

# Variables declared with use vars() are like those declared
# with our(): belong to a package; not private; and not new.
# However, their scoping is package-based rather than lexical.
for (1 .. 9){
    use vars qw($uv);
    $uv ++;
}

# Even though we are outside the lexical scope where the
# use vars() variable was declared, we have direct access
# because the package has not changed.
print __PACKAGE__, " >> uv=$uv\n";

# And we can access it from another package.
package Bubb;
print __PACKAGE__, " >> main::uv=$main::uv\n";

11

スコープへの対処は、Perlスコープルールの概要です。ourテキストの本文で説明されていないほど古くなっています。これは、最後の「メモ」セクションで説明されています。

この記事では、パッケージ変数と動的スコープ、およびそれが字句変数と字句スコープとどのように異なるかについて説明します。


5

myローカル変数にour使用され、グローバル変数に使用されます。

PerlのVariable Scoping:basicsを読んでください


16
ローカルとグローバルという言葉を慎重に投げ捨ててください。適切な用語は、語彙とパッケージです。Perlで真のグローバル変数を作成することはできませんが、$ _のように既に存在するものがあります。ローカルは、(myで作成された)字句変数ではなく、ローカライズされた値(ローカルで作成された)を持つパッケージ変数を参照します。
Chas。オーエンス

${^Potato}グローバルです。どこで使用しても同じ変数を参照します。
MJD 2013年

5

私はめちゃくちゃになったPerlの字句宣言についていくつかの落とし穴に遭遇したことがあり、これもこの質問に関連しているので、ここに要約を追加します。

1.定義または宣言?

local $var = 42;
print "var: $var\n";

出力はvar: 42です。しかし、それがlocal $var = 42;定義か宣言かはわかりませんでした。しかし、これはどうですか:

use strict;
use warnings;

local $var = 42;
print "var: $var\n";

2番目のプログラムはエラーをスローします。

Global symbol "$var" requires explicit package name.

$varは定義されていません。つまりlocal $var;、単なる宣言です。を使用localして変数を宣言する前に、その変数が以前にグローバル変数として定義されていることを確認してください。

しかし、なぜこれが失敗しないのでしょうか?

use strict;
use warnings;

local $a = 42;
print "var: $a\n";

出力は次のとおりvar: 42です。

ので、それはです$aだけでなく、$bPerlで事前に定義されたグローバル変数です。ソート機能を覚えていますか?

2.語彙的かグローバルか?

私はPerlを使い始める前はCプログラマでした。そのため、字句変数とグローバル変数の概念は私には簡単に思えます。Cの自動変数と外部変数に対応しているだけです。ただし、小さな違いがあります。

Cでは、外部変数は関数ブロックの外部で定義された変数です。一方、自動変数は、ファンクションブロック内で定義される変数です。このような:

int global;

int main(void) {
    int local;
}

Perlでは、物事は微妙です。

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

出力はvar: 42です。$var関数ブロックで定義されていても、グローバル変数です!実際にはPerlでは、すべての変数がデフォルトでグローバルとして宣言されています。

レッスンは、常にuse strict; use warnings;Perlプログラムの先頭に追加することです。これにより、プログラマーは字句変数を明示的に宣言する必要があり、当然のことと誤解されないようになっています。


["ここで[$ aと$ b in]ソートを覚えておく]の詳細(stackoverflow.com/a/26128328/1028230)。Perlが私を驚かせ続けることは決してありません。
ルフィン、2015

4

perldocのは、私たちの良い定義があります。

変数にストレージを割り当て、現在のスコープ内で使用するために単純な名前をそのストレージに関連付けるmyとは異なり、現在のスコープ内で使用するために単純な名前を現在のパッケージのパッケージ変数に関連付けます。言い換えると、私たちのスコープルールはmyと同じですが、必ずしも変数を作成するわけではありません。


2

これは質問にいくらか関連しているだけですが、「私」(ローカル)では使用できない「our」(パッケージ)変数で使用できる(私にとって)あいまいなperl構文を発見しました変数。

#!/usr/bin/perl

our $foo = "BAR";

print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";

出力:

BAR
BAZ

これを 'our'を 'my'に変更すると機能しません。


1
そうではありません。$ foo $ {foo} $ {'foo'} $ {"foo"}はすべて、変数の割り当てまたは逆参照に対して同じように機能します。上記の例でたちをスワップすることは機能します。あなたがおそらく経験したことは、$ main :: fooや$ :: fooなどのパッケージ変数として$ fooを逆参照しようとしていることです。
Cosmicnet 2014年

ただ、V5.20を使用して再テストし、それは間違いで同じ出力を与えるものではありません、私の(それが二回BARを印刷します。)
ミーシャゲイル

1
私のテスト(Windowsの場合): perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"出力:barbaz perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"出力:barbaz perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"出力:barbar したがって、私のテストでは同じ罠に陥りました。$ {foo}は$ fooと同じです。角かっこは補間時に役立ちます。$ {"foo"}は、実際にはメインシンボルテーブルである$ main :: {}までのルックアップです。パッケージスコープの変数のみが含まれているためです。
Cosmicnet 2014年

1
$ {"main :: foo"}、$ {":: foo"}、および$ main :: fooは、$ {"foo"}と同じです。perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"この文脈では$ {"foo"}が$ {"test :: foo"}と等しくなるので、省略表現はパッケージ依存の動作です。高度なPerlプログラミングブックと同様に、Symbol Tables and Globsにもいくつかの情報があります。以前の間違いでごめんなさい。
Cosmicnet 2014年

0
print "package is: " . __PACKAGE__ . "\n";
our $test = 1;
print "trying to print global var from main package: $test\n";

package Changed;

{
        my $test = 10;
        my $test1 = 11;
        print "trying to print local vars from a closed block: $test, $test1\n";
}

&Check_global;

sub Check_global {
        print "trying to print global var from a function: $test\n";
}
print "package is: " . __PACKAGE__ . "\n";
print "trying to print global var outside the func and from \"Changed\" package:     $test\n";
print "trying to print local var outside the block $test1\n";

これを出力します:

package is: main
trying to print global var from main package: 1
trying to print local vars from a closed block: 10, 11
trying to print global var from a function: 1
package is: Changed
trying to print global var outside the func and from "Changed" package: 1
trying to print local var outside the block 

"use strict"を使用すると、スクリプトの実行中にこのエラーが発生します。

Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.

何らかの説明をお願いします。このようなコードのダンプが適切と見なされることはほとんどありません。
スコットソルマー2014

簡単に言うと、私たち(名前saisとして)は、スクリプトの任意の場所(関数、ブロックなど)からその変数を使用するための変数declirationであり、デフォルトで(宣言されていない場合)すべての変数は「main」に属していますパッケージでは、スクリプトで別のパッケージを除外した後でも、変数を使用できます。ブロックまたは関数で宣言されている場合の「my」変数は、そのブロック/関数でのみ使用できます。「my」変数がブロック内で閉じられていないことが宣言されている場合、それはscriot内、閉じられたブロック内、または「our」変数として関数内の任意の場所で使用できますが、パッケージが変更された場合は使用できません
ラビブーフニク14

上記のスクリプトは、デフォルトで「main」パッケージにいることを示しています。次に、スクリプトは「main」パッケージから「our」変数を出力し(ブロックで閉じていません)、関数で2つの「my」変数を宣言します。その関数からそれらを出力します。次に、別の関数から「our」変数を出力して、関数で使用できることを示します。次に、パッケージを "changed"( "main"ではなく)に変更し、 "our"変数を再び正常に出力します。次に、関数の外で「my」変数を出力しようとして失敗しました。スクリプトは、「our」と「my」の使用法の違いを示しています。
Lavi Buchnik 2014

0

次のプログラムを使用してみてください:

#!/usr/local/bin/perl
use feature ':5.10';
#use warnings;
package a;
{
my $b = 100;
our $a = 10;


print "$a \n";
print "$b \n";
}

package b;

#my $b = 200;
#our $a = 20 ;

print "in package b value of  my b $a::b \n";
print "in package b value of our a  $a::a \n";

これは私と私たちの違いを説明しています。my変数は中括弧の外ではスコープ外になり、ガベージコレクションされますが、私たちの変数はまだ存続しています。
Yugdev 2015年

-1
#!/usr/bin/perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;

このコードのデモンストレーションの意味を説明できますか?なぜourmy違いますか?この例はそれをどのように示していますか?
Nathan Fellman、2013年

-1

インタプリタが実際に何であるかを考えてみましょう。これはメモリに値を格納し、プログラム内の命令がそれらの値内に指定されている名前でそれらの値にアクセスできるようにするコードの一部です。したがって、インタープリターの大きな仕事は、インタープリターが保管する値にアクセスするために、これらの命令で名前をどのように使用すべきかという規則を形作​​ることです。

「my」に遭遇すると、インタープリターはレキシカル変数を作成します。インタープリターは、ブロックの実行中にのみ、その構文ブロック内からのみアクセスできる名前付きの値です。「our」に遭遇すると、インタープリターはパッケージ変数の字句エイリアスを作成します。それは、インタープリターがそれ以降、字句変数の名前として処理すると想定される名前を、ブロックが完了するまでパッケージの値にバインドします。同じ名前の変数。

その結果、レキシカル変数を使用しているように見せかけ、パッケージ変数の完全修飾に対する「厳密な使用」のルールを回避できます。インタープリターは最初に使用されるときに自動的にパッケージ変数を作成するため、「our」を使用することの副作用として、インタープリターがパッケージ変数も作成することがあります。この場合、2つのものが作成されます。「use strict」(パッケージの名前と2つのコロンが前に付加されます)によって要求されたとおりにインタープリターが適切に指定されている場合、インタープリターがどこからでもアクセスできるパッケージ変数その字句エイリアスです。

出典:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.