質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • プログラミング言語

    667questions

    プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

なんとなく気になったんですが

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 585

KazuhiroHatano

score 1415

関数の実行ごとに名前空間が違う、と言えばいいのか
同じ関数を実行してもローカル変数はそれぞれが持ちますよね

function hoge(){
    if(!isset($b))$b=0;
    echo $b++;
}
hoge();
hoge();
hoge();

これの出力は000で012とかになったりはしません

これっておよそどの言語でも同じなんでしょうか?

それとも関数ごとで変数を共有するような言語もあったりするんでしょうか?
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+5

これは名前空間と言うより、変数のスコープとライフサイクルのお話です。

 スコープ

ほとんどの言語には変数にスコープというのがあります。スコープというのはその変数が「見える場所はどこか」ということです。スコープは大きく分けると二つです。
  • グローバルスコープ: プログラムのどこからでも見えるスコープです。言語によってはそのままどこでも使える場合と、関数内等で使用する場合は何かしらの宣言やプリフィックス等を付ける必要がある場合があります。更に分けると2種類あります。
1. グローバルスコープ: 他のライブラリやソースファイルからもどこからでも見えます。グローバル変数と呼びます。
2. ファイルスコープ: そのプログラムのファイル内でのみ見えます。採用している言語は少なく、C/C++ぐらいです。こちらもグローバル変数と呼ぶのですが、区別する場合はC/C++でstaticをつけることから静的グローバル変数(言葉の意味としてはまったくもってよくわからないのですが)と呼ばれることもあります。
  • ローカルスコープ: ある特定の範囲内でのみ見えるスコープです。更に分けると4種類あります。
1. 関数スコープ: その関数内でのみ見えます。ローカル変数と呼ばれます。
2. ブロックスコープ: そのブロック(例えば、for文の中とか、何がブロックを構成するかは言語によって異なる)でのみ見えます。こちらもローカル変数と呼ばれます。関数スコープと区別してブロックローカル変数と呼ぶ場合もあります。
3. クラススコープ: クラスとそのクラスのインスタンスから見えます。基本的にはクラスとインスタンスで共用されます。クラス変数と呼ばれます。
4. インスタンススコープ: インスタンスでのみ見えます。基本的にはインスタンス毎に別々に持ちます。インスタンス変数と呼ばれます。

各スコープにおいて、見える範囲が異なれば、名前空間が異なるようになります。同じ名前を付けても、別のものとして扱います。

言語によっては、全てのスコープが用意されているわけではありません。

 ライフサイクル

変数のライフサイクルとはいつ生成されていつ破棄されるかです。スコープによって動作が異なります。
  • グローバルスコープ: プログラム開始時または宣言時やライブラリのロード時に生成されます。明示的に破棄しない限り、プログラムが終了するまで破棄されることはありません。
  • ローカルスコープ: 大きく自動(auto)と静的(static)に分かれます。
1. 自動: 該当するスコープ開始時(関数スコープであれば関数開始時)または宣言時に生成されます。ほとんどの場合は、スコープ終了時に自動的に破棄されます。ほとんどの変数がこれに該当します。
2. 静的: プログラム開始時または該当するスコープのロード時に生成され、プログラム終了時または該当するスコープ自体の破棄に破棄されます。宣言時に静的であるとした場合や、クラススコープが該当します。ローカル変数のうち静的な場合を区別して静的ローカル変数とよぶます。

言語によって、細かい動作が異なります。静的ローカル変数が用意されていない言語もあります。

 宣言の仕方

どの変数がどれになるかは最初の宣言の場所と宣言の仕方によって異なります。例えば、PHPの場合、関数外で宣言すればグローバルスコープに、関数内で宣言すれば関数スコープになります。また、関数スコープの変数にstaticを付けると静的になります。

質問で書いているPHPのコードにおいて、$bはただのローカル変数です。関数内でしか見えず、かつライフサイクルは自動になりますので、関数終了時に自動的に破棄されます。そのため、毎回0で初期化されるため、出力が000になったのです。では、出力が012になるようにPHPを修正する例を二つあげます。

1. グローバル変数を使う。
<?php
$b  = 0;
function hoge(){
    global $b;
    echo $b++;
}
hoge();
hoge();
hoge();

$bはグローバル変数になります。関数内で使う場合は、global $b;としておく必要があります。グローバル変数はプログラム全体で一つだけであり、自動的に破棄されません。ですので、数はインクリメントされていきます。

2. 静的ローカル変数を使う。
<?php
function hoge(){
    static $b = 0;
    echo $b++;
}
hoge();
hoge();
hoge();

ロカール変数にstatic修飾子を付けているため、$bは静的ローカル変数になります。静的ローカル変数は自動的に破棄されなくなり、二回目の時は再利用されます(0を代入するという初期化は最初の一回のみで、二回目以降はされません)。ですので、こちらもインクリメントされます。

PHPでのさらにより詳しい動作は下記マニュアルを参考にしてみてください。
参考文献: PHP マニュアル: 変数のスコープ

言語によって宣言の仕方や使い方が違いますが、概念はほぼ同じ、同じようなことができるようになっています。各言語のマニュアル等を参考にしてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/10 15:09

    詳しい解説ありがとうございます

    イテレータがブロックになる言語というのもあるのですね
    PHPで関数にもstaticが使えるというのを初めて知りました
    オブジェクト指向特有の概念でクラスにしか
    ないものだと思い込んでしまっていました
    やはり付焼きばかりで勉強してるといろいろと抜けてますね

    キャンセル

+1

多くの言語では、基本的には、関数のローカル変数は、関数が呼び出された時点で新規に作成されますので、毎回異なる実体と言うことになります。

言語によっては、毎回作成されるので無く、プログラム実行ごとに1つ、つまり、複数回の関数呼び出しでも同じ実体を共有するようなローカル変数を宣言することも出来ます。例えばCだと、static修飾子をつけるとそうなります。

例:
#include <stdio.h>
int foo(){
    static int x=0;
    x++;
    return x;
}

main(){
    printf("%d\n",foo());  // => 1 を出力
    printf("%d\n",foo());  // => 2 を出力
    printf("%d\n",foo());  // => 3 を出力
}

現代の多くの言語と違って、fortranだと、特に指定しなくても実体は1つです。
       integer function  foo() result(ret)
       integer :: x = 0
       x = x + 1
       ret = x
       end
    
       integer :: foo
       print *, foo()      1を出力
       print *, foo()      2を出力
       print *, foo()      3を出力
       end

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/10 15:13 編集

    回答ありがとうございます

    fortran
    にわかなもので見たことも聞いたこともない言語です
    しかし実際そういう言語ってのはあるもんなんですね

    キャンセル

0

名前空間を出す当たり、オブジェクトの話をしようとしているように見えますが
例文は、オブジェクトとは関係ないです。

hoge();で、
hoge()メソッドが呼び出され、
変数bが未定義であれば、b=0で定義
標準出力へbを出力し、
bをインクリメントする。
そして処理が終わるので、生成した変数は破棄される。

というのが3回繰り返されるという実装ですね。

同じローカル変数ですが、
b=0で定義→破棄
を繰り返すので、000という出力になります。

繰り返しになりますが、
たとえ暗黙・無意識でも、定義と破棄をする実装をしています。

言語が違っても、定義と破棄をする実装であれば、結果は同じになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/10 15:40

    回答ありがとうございます

    大概の言語は破棄まで自動的にやってくれますね
    関数の実行に際してはデストラクタの実装とかメモリの解放なんて
    考えなくていいのが当たり前で便利な世の中です

    キャンセル

0

これっておよそどの言語でも同じなんでしょうか?
概ねYesです。
少ない理由は関数のスコープを独立させないと使い勝手が悪いからです。
ただ言語は自由に作れますし、その挙動は仕様次第なので存在し得ないわけではありません。

これはフェイクですが、クロージャーは一見禁を破っているように見えますね。
//jQuery
$(function(){
    a=1;
    function b(){
        console.log(a);
        a++;
    }
    b(); // 1
    b(); // 2
    b(); // 3
});
他には確か8bitPCの頃のベーシックなんかは、サブルーチンの変数はメインルーチンの変数と共用だったと思います。(うろ覚え)
Interpreterデザインパターンの習作として自作したスクリプト言語なんかだと、ユーザ定義関数機能を実装しながら面倒でスコープを実装せずに終わったものなど幾らでも存在すると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/10 06:55

    そのコードですと、aはグローバル変数になっちゃうので、クロージャー云々もなんも関係なく共通のaを見に行っちゃいます。aの前にvarを付けませんと…。

    キャンセル

  • 2015/10/10 15:29

    回答ありがとうございます

    javascriptの宣言なしの変数は全部グローバル変数って仕様は
    正直あんまりキレイな仕様ではないですよね

    javascriptだとstatic変数というのは_prototypeにもたせた変数ってカンジでしょうか
    プロトタイプベースの認識が「中途半端なオブジェクト指向」なので
    わりといい加減な解釈でよしとしちゃってるカンジですが

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • プログラミング言語

    667questions

    プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。