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

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

新規登録して質問してみよう
ただいま回答率
85.50%
プログラミング言語

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

Q&A

解決済

4回答

2656閲覧

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

KazuhiroHatano

総合スコア7802

プログラミング言語

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

0グッド

1クリップ

投稿2015/10/09 17:31

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

PHP

1function hoge(){ 2 if(!isset($b))$b=0; 3 echo $b++; 4} 5hoge(); 6hoge(); 7hoge();

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

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

それとも関数ごとで変数を共有するような言語もあったりするんでしょうか?

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

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

スコープ

ほとんどの言語には変数にスコープというのがあります。スコープというのはその変数が「見える場所はどこか」ということです。スコープは大きく分けると二つです。

  • グローバルスコープ: プログラムのどこからでも見えるスコープです。言語によってはそのままどこでも使える場合と、関数内等で使用する場合は何かしらの宣言やプリフィックス等を付ける必要がある場合があります。更に分けると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

1<?php 2$b = 0; 3function hoge(){ 4 global $b; 5 echo $b++; 6} 7hoge(); 8hoge(); 9hoge();

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

  1. 静的ローカル変数を使う。

PHP

1<?php 2function hoge(){ 3 static $b = 0; 4 echo $b++; 5} 6hoge(); 7hoge(); 8hoge();

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

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

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

投稿2015/10/09 23:07

編集2015/10/09 23:23
raccy

総合スコア21733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KazuhiroHatano

2015/10/10 06:09

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

0

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

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

例:

C

1#include <stdio.h> 2int foo(){ 3 static int x=0; 4 x++; 5 return x; 6} 7 8main(){ 9 printf("%d\n",foo()); // => 1 を出力 10 printf("%d\n",foo()); // => 2 を出力 11 printf("%d\n",foo()); // => 3 を出力 12}

現代の多くの言語と違って、fortranだと、特に指定しなくても実体は1つです。

fortran

1 integer function foo() result(ret) 2 integer :: x = 0 3 x = x + 1 4 ret = x 5 end 6 7 integer :: foo 8 print *, foo() 1を出力 9 print *, foo() 2を出力 10 print *, foo() 3を出力 11 end

投稿2015/10/09 22:49

編集2015/10/10 00:14
otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KazuhiroHatano

2015/10/10 06:47 編集

回答ありがとうございます fortran にわかなもので見たことも聞いたこともない言語です しかし実際そういう言語ってのはあるもんなんですね
guest

0

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

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

これはフェイクですが、クロージャーは一見禁を破っているように見えますね。

javascript

1//jQuery 2$(function(){ 3 a=1; 4 function b(){ 5 console.log(a); 6 a++; 7 } 8 b(); // 1 9 b(); // 2 10 b(); // 3 11});

他には確か8bitPCの頃のベーシックなんかは、サブルーチンの変数はメインルーチンの変数と共用だったと思います。(うろ覚え)
Interpreterデザインパターンの習作として自作したスクリプト言語なんかだと、ユーザ定義関数機能を実装しながら面倒でスコープを実装せずに終わったものなど幾らでも存在すると思います。

投稿2015/10/09 18:47

編集2015/10/09 18:50
hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2015/10/09 21:55

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

2015/10/10 06:29

回答ありがとうございます javascriptの宣言なしの変数は全部グローバル変数って仕様は 正直あんまりキレイな仕様ではないですよね javascriptだとstatic変数というのは_prototypeにもたせた変数ってカンジでしょうか プロトタイプベースの認識が「中途半端なオブジェクト指向」なので わりといい加減な解釈でよしとしちゃってるカンジですが
guest

0

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

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

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

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

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

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

投稿2015/10/09 18:03

TetsujiMiwa

総合スコア1124

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KazuhiroHatano

2015/10/10 06:40

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問