Page Top

今回は… anchor.png

変数のスコープについて説明します。
変数の寿命とかなり似ている部分ですが、違いはあります。
どのくらい違うかというと…
寿命が「時間」のようなものであるのに対し、スコープはコード内における「場所」のようなものを指します。
アクセスすることのできる場所…見える場所という意味です。

変数の寿命ではブロックを越えてアクセスしようとしたらだめだというお話をしました。
でも、実際にはポインタで無理やり参照してコンパイルも成功していました。
でも、今回のサンプルコードではコンパイルが通りません。
アクセスできる場所にあるかどうか、その辺がスコープにかかわってくるものです。
詳細は以下のサンプルコードをご覧ください。

Page Top

今回のミソ anchor.png

  • スコープはアクセス*1できる範囲のこと
  • 同じあるいはネストしたブロック内のスコープを、ローカルスコープと言う
  • ローカルスコープからのみアクセスできる変数をローカル変数*2という
Page Top

サンプルコード anchor.png

filesample1201.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 
-
-
!
-
-
!
-
!
|
-
-
!
-
|
|
!
|
-
!
|
-
|
|
!
|
-
!
|
-
 
 
 
!
|
-
-
!
-
|
|
!
 
-
|
|
!
 
-
!
|
|
-
!
int main(char[][] args)
{
    // ブロック1開始
    int a=1;
    {
        // ブロック2開始
        
        // ブロック2で変数bを宣言
        int b=0;
        
        if(a==1){
            // ブロック3開始
            
            // OK
            // ブロック1とブロック2が終わっていないのでaもbも使える。
            // ブロック3で変数cを宣言
            int c=a+b;
            
            // ブロック3終了
        }
        
        // エラー。
        // ブロック2は終わっていないのでbは使えるが、
        // ブロック3はすでに終わっているのでcという変数は使えない
        c = b+1;
        
        // ブロック2終了
    }
    
    // エラー。
    // ブロック1は終わっていないのでaは使えるが、
    // ブロック2とブロック3が終わっているので
    // bとcの変数は使えない
    a = b+c;
    
    {
        // ブロック4開始
        
        // OK
        // すでにブロック2は終わっており、
        // 再び変数 b が宣言できるようになっている。
        int b = 100;
        
        // エラー
        // すでにブロック1でaが宣言されているので、
        // もう一度aを宣言することはできない。
        int a = 400;
        
        // ブロック4終了
    }
    
    return 0;
    // ブロック1終了
}

*3

Page Top

実行結果 anchor.png

1
2
3
4
5
$ dmd -run sample1201.d
sample1201.d(25): Error: undefined identifier c
sample1201.d(34): Error: undefined identifier b
sample1201.d(34): Error: undefined identifier c
sample1201.d(47): Error: shadowing declaration sample1201.main.a is deprecated
Page Top

まとめ anchor.png

このように、変数を使える範囲(スコープ)が決められているので、有効に利用するといいと思います。
たとえば、tempやhogeとかfugaなどというような一時的な作業用の変数などを使う際には "{" と "}" で囲んで変数限定してやるのがいいと思います。
ちなみに、今回やったスコープ内でのみアクセスすることのできる変数を、ローカル変数*2と言ったりもします。
また、このようなスコープをローカルスコープと言います。
ローカルスコープはたとえば関数内で宣言された変数に対してはその関数内でしか使うことができない、というようなやつのことです。

次は、このブロック内で有効になるというスコープを無視してアクセスすることのできるグローバル変数*4というものについて説明します。
お次へどうぞ~

Page Top

#02 - 大域変数 anchor.png

Page Top

今回は… anchor.png

グローバルスコープで宣言される変数「グローバル変数(大域変数)」について説明します。

まず、グローバルスコープについてですが、関数の外側のあたり…その中でも特に、モジュール(ファイル)の外からもアクセスすることができる範囲をグローバルスコープといいます。
このスコープを持つ変数はグローバル変数と言って、どこからでもアクセスすることのできる変数になります。
これまで扱った関数は、グローバルスコープなので、基本的にはどこからでもアクセスすることができますね。
グローバル変数のほうは、まぁ、普通、あんまり作りませんが。
ちなみに、この大域変数の寿命は、やはりプログラムが開始されてから終了するまでとなっています。
この大域変数を、寿命の観点から見て言えば外部変数と言ったりもします。

Page Top

今回のミソ anchor.png

  • モジュール(ファイル)を越えてもアクセスできる範囲をグローバルスコープという
  • グローバルスコープは、つまり関数や構造体の外側の部分
  • グローバルスコープの変数をグローバル変数(大域変数)という。
  • グローバルスコープの変数や関数は、面倒でなければできる限りpublicをつけるといい
Page Top

サンプルコード anchor.png

filesample1202p.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
 
-
!
 
-
!
 
 
-
-
!
-
|
|
!
|
-
|
|
!
|
-
!
|
-
!
|
-
!
!
import std.stdio;
 
// グローバル変数 global_x を定義
int global_x = 10;
 
// グローバル変数の場合、できればpublicとつけておくとわかりやすくなる
public int global_y = 20;
 
int main(char[][] args)
{
    // ブロック1 開始
    
    // グローバル変数はグローバルスコープを持っているので
    // どこからでもアクセス可能
    // このモジュール(ファイル)以外からでもアクセス可能
    writeln( global_x + 10 * global_y );
    
    // グローバルスコープにglobal_xがあるが、
    // ローカルスコープでも定義することができる。
    // ただし、非常に混乱するバグのもとになるためお勧めしない。
    int global_x = 5;
    
    // この場合、ローカルコープの変数を使いたい場合はそのまま書けばよい
    writeln(global_x);
    
    // グローバルスコープの変数を使いたい場合は変数名の前に.を付ける
    writeln(.global_x);
    
    // ブロック1 終了
    return 0;
}
+  Tango用はこちら
filesample1202t.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
 
-
!
 
-
!
 
 
-
-
!
-
|
|
!
|
-
|
|
!
|
-
!
|
-
!
|
-
!
!
import tango.io.Stdout;
 
// グローバル変数 global_x を定義
int global_x = 10;
 
// グローバル変数の場合、できればpublicとつけておくとわかりやすくなる
public int global_y = 20;
 
int main(char[][] args)
{
    // ブロック1 開始
    
    // グローバル変数はグローバルスコープを持っているので
    // どこからでもアクセス可能
    // このモジュール(ファイル)以外からでもアクセス可能
    Stdout( global_x + 10 * global_y ).newline;
    
    // グローバルスコープにglobal_xがあるが、
    // ローカルスコープでも定義することができる。
    // ただし、非常に混乱するバグのもとになるためお勧めしない。
    int global_x = 5;
    
    // この場合、ローカルコープの変数を使いたい場合はそのまま書けばよい
    Stdout(global_x).newline;
    
    // グローバルスコープの変数を使いたい場合は変数名の前に.を付ける
    Stdout(.global_x).newline;
    
    // ブロック1 終了
    return 0;
}
Page Top

実行結果 anchor.png

1
2
3
4
$ dmd -run sample1202p.d
210
5
10
Page Top

まとめ anchor.png

どこからでもアクセスすることのできる範囲「グローバルスコープ」と、「グローバル変数」について説明しました。
サンプル内で説明されているように、グローバル変数を定義してある場合、可能な限りローカルスコープなどで同じ名前をつけないようにしたほうがいいでしょう。非常に混乱します。

次は、そのモジュール(ファイル)内からならアクセスできるけれど、ほかのモジュール(ファイル)からはアクセスすることができないという ファイルスコープについて説明します。
お次へどうぞ~

Page Top

#03 - ファイルスコープ anchor.png

Page Top

今回は… anchor.png

ファイルスコープについて説明します。

まず、前回のグローバルスコープですが、これにはひとつ懸念があります。
もしかしたら、自分の知らないところで勝手に値が書き換えられてしまうかもしれないというところです。
グローバルスコープはモジュール(ファイル)を越えてアクセスすることができるので、別のファイル内で値が変更されてしまうという危険性があるのです。
これを避けるために、その定義をしたモジュール(ファイル)内からしかアクセスすることのできないスコープ「ファイルスコープ」というものがあります。
グローバルスコープで変数を定義する場合にはpublicとしましたが、ファイルスコープの場合、privateとします。

ちなみに、さっきからファイル変数とか言わずにファイルスコープの変数とかいうのは、ファイル変数なんて単語は普通使わないからです。
グローバルスコープの変数は、グローバル変数。
ローカルスコープの変数は、ローカル変数。
でも、ファイルスコープの変数はファイルスコープの変数。

Page Top

今回のミソ anchor.png

  • モジュール(ファイル)内のどこからでもアクセスできる範囲をファイルスコープという
  • ファイルスコープの変数や関数は、つまり関数や構造体の外側の部分に記述し、さらにprivateとつける。
Page Top

サンプルコード anchor.png

filesample1203.d
Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 
 
 
-
!
 
 
-
-
!
-
|
|
|
!
|
-
!
!
// ファイルスコープの変数 file_x を定義
private int file_x = 10;
 
// ファイルスコープ変数の場合、必ず private とつける
private int file_y = 20;
 
int main(char[][] args)
{
    // ブロック1 開始
    
    // ファイルスコープなのでファイル内なら
    // どこからでもアクセス可能
    // ただし、このモジュール(ファイル)以外からはアクセス不可能。
    // それ以外はおおむねグローバルスコープと扱いは同じです。
    int x = file_x + 10 * file_y;
    
    // ブロック1 終了
    return 0;
}

*3

Page Top

実行結果 anchor.png

1
$ dmd -run sample1203.d
Page Top

まとめ anchor.png

というわけで、グローバルスコープのときとほとんど変わりませんが、ファイルの外部からは隠ぺいすることができているはずです。
グローバル変数よりはこっちのほうが使う機会が多いですね。
あんまり情報を駄々漏れにするのはよくありません。
複雑化してデバッグがしにくくなったり、名前が衝突*5したりしますから…。

Page Top

#summary - まとめ anchor.png

Page Top

第12章のミソ anchor.png

  • スコープはアクセス*1できる範囲のこと
  • 同じあるいはネストしたブロック内のスコープを、ローカルスコープと言う
  • ローカルスコープからのみアクセスできる変数をローカル変数*2という
  • モジュール(ファイル)を越えてもアクセスできる範囲をグローバルスコープという
  • グローバルスコープは、つまり関数や構造体の外側の部分
  • グローバルスコープの変数をグローバル変数(大域変数)という。
  • グローバルスコープの変数や関数は、面倒でなければできる限りpublicをつけるといい
  • モジュール(ファイル)内のどこからでもアクセスできる範囲をファイルスコープという
  • ファイルスコープの変数や関数は、つまり関数や構造体の外側の部分に記述し、さらにprivateとつける。
Page Top

宿題 anchor.png

ファイルスコープとローカルスコープ、自動変数の寿命と静的変数の寿命がわかっているぜ!って「思われる」ようなプログラムを一つ組んでみましょう。

Page Top

コメント anchor.png

さて、今回はスコープについてやりました。 できるだけ変数の寿命とは違うイメージになるように記述しましたが…
さて、次回のD言語入門講座は…
「構造体のメンバをまとめて定義する方法(with文)」について説明していきます。

そんなわけで、宿題できたら、あるいは予想ついたら次にいきましょう~


Page Top

投票とコメント anchor.png

Choices Vote
大変参考になった0  
参考になった2  
あまり参考にならなかった0  
まったく参考にならなかった0  

No comment. コメント​/Articles​/D言語入門講座​/第12章 - スコープEdit

Name:

*1 変数や関数などを使うことができるという意味で。
*2 他にも局所変数や内部変数といった呼び方もあります
*3 今回はTangoもPhobosも共通です。
*4 大域変数という呼び方もあります
*5 グローバルスコープで説明した、名前の混乱のこと

Front page   Freeze Diff Backup Copy Rename ReloadPrint View   New Page Page list Search Recent changes   Help   RSS of recent changes (RSS 1.0) RSS of recent changes (RSS 2.0) RSS of recent changes (RSS Atom) Powered by xpWiki
Counter: 2061, today: 1, yesterday: 0
Princeps date: 2009-09-26 (Sat) 00:28:28
Last-modified: 2009-09-26 (Sat) 00:28:28 (JST) (4089d) by SHOO
メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu