プログラミング/変数
プログラミングにおいて、変数は非常に重要な概念です。変数を理解することは、プログラミングの基礎を理解する上で欠かせないステップです。
変数は、プログラム中で使用される値やデータを格納するための仕組みです。変数には、名前と値があります。名前は変数を識別するためのものであり、値はその変数に格納されたデータを表します。
変数を使うことで、同じ値を何度も使用する必要がある場合に、簡単にその値を参照できます。また、変数に新しい値を代入することで、プログラムの動作を変更することができます。
本書では、変数の基本的な概念から始めて、より高度な使い方や実践的な応用方法までを解説していきます。変数を理解することで、プログラミングにおける基本的な制御構造や関数の理解にも役立つことでしょう。
var x = { prop: 1 }; var y = x; x.prop = 2; console.log(y.prop);
実行結果は2になります。これは、xがオブジェクトを参照しているため、yも同じオブジェクトを参照しているためです。そのため、xのプロパティを変更すると、yも同じ変更を反映します。
静的型付け言語と変数
編集プログラミング言語には、静的型付け言語と動的型付け言語の2種類があります。
静的型付け言語では、変数に対してその型を明示的に宣言する必要があります。変数が宣言されると、その変数はその型に制限され、別の型の値を代入することはできません。静的型付け言語は、コンパイル時に型チェックを行い、実行時に予期しない型のエラーを防ぐことができます。
例えば、JavaやC++は静的型付け言語です。以下の例では、変数xがint型で宣言されているため、xには整数値しか代入できません。
int x = 10; x = "Hello World"; // エラーが発生する
静的型付け言語の利点は、コンパイル時にエラーを発見できることや、型に対する厳密な制限によって安全性を高めることができることです。ただし、変数の型を明示的に宣言する必要があるため、コードの記述量が多くなる傾向があります。
静的型付け言語では、変数が型を持ちます。
動的型付け言語と変数
編集動的型付け言語では、変数が宣言されるときにその型を明示的に宣言する必要はありません。変数には、代入される値に応じて適切な型が自動的に割り当てられます。つまり、変数が持つ値に応じて型が動的に変化するため、実行時に型チェックが行われます。
例えば、PythonやRubyは動的型付け言語です。以下の例では、変数xが最初に整数値として宣言されていますが、文字列を代入することができます。
x = 10 x = "Hello World" # エラーは発生しない
動的型付け言語の利点は、コードの記述量が少なくなることや、柔軟性が高いことです。一方、実行時に型チェックを行うため、予期しない型のエラーが発生する可能性があることや、静的型付け言語に比べて実行速度が遅くなることがあります。
動的型付け言語では、変数に型はなく、変数が保持している値に型があります。
関数型プログラミング言語と変数
編集関数型言語では、変数には常に値が割り当てられ、再代入はできません。また、変数の型は宣言されたときに定まり、変更することはできません。
変数の値は、不変であるため、関数型言語では、値を引数として受け取り、新しい値を返す関数を重視します。つまり、関数は状態を変更するのではなく、値を受け取り、変換して返すものとして扱われます。
例えば、HaskellやOCamlは関数型言語です。以下の例では、変数xには数値が割り当てられていますが、再代入することはできません。
x = 10 x = 20 -- エラーが発生する
関数型言語の利点は、変数の値が不変であるため、プログラムの正確性が高くなり、スレッドセーフであることや、関数の再利用性が高くなることです。一方、状態を変更する必要がある場合や、変数の値を更新する必要がある場合には不向きであることがあります。
スコープ
編集スコープとは、変数が参照可能な範囲を指します。プログラムの中で変数が定義される場合、その変数はその定義された場所によって、アクセス可能な範囲が異なります。以下に、主なスコープの種類を紹介します。
グローバルスコープ
編集プログラムの全体でアクセス可能なスコープです。通常、グローバル変数やグローバル関数が定義されます。
- JavaScript
var x = 10; // グローバル変数 function func() { x = 20; console.log(x); } func(); // 出力: 20 console.log(x); // 出力: 20
関数スコープ
編集関数内で定義された変数が属するスコープです。関数内で定義された変数は、関数の内部でのみアクセス可能です。
- JavaScript
function func() { var x = 10; // 関数スコープ内で定義された変数 console.log(x); } func(); // 出力: 10 console.log(x); // エラーが発生する
ブロックスコープ
編集ブロック内で定義された変数が属するスコープです。ブロックスコープは、通常、if文やfor文、while文などの制御構造の内部で使用されます。
- JavaScript
if (true) { let x = 10; // ブロックスコープ内で定義された変数 console.log(x); } console.log(x); // エラーが発生する
レキシカルスコープ
編集レキシカルスコープとは、変数が定義された場所によって、変数のスコープが決定される仕組みです。レキシカルスコープを採用している言語では、変数のスコープは、その変数が定義された場所から始まり、その変数を含む親スコープの範囲まで及びます。
クロージャとは、関数とその関数が定義されたスコープとの結びつきを持つオブジェクトのことです。クロージャは、外部からアクセスできない変数を保持し、その変数にアクセスする関数を提供します。これにより、関数内で定義された変数を、その関数が呼び出されるたびに保持できます。
以下に、レキシカルスコープとクロージャの例を示します。
- JavaScript
function outerFunc() { var x = 10; // 外側の関数内で定義された変数 function innerFunc() { console.log(x); // 外側の関数の変数にアクセスする } return innerFunc; // innerFunc関数を返す } var func = outerFunc(); // outerFunc関数を実行して、innerFunc関数を取得する func(); // outerFunc関数が終了した後でも、innerFunc関数がx変数にアクセスできる
この例では、outerFunc
関数内で定義された変数x
にアクセスするために、innerFunc
関数がクロージャを使用しています。outerFunc
関数が終了した後でも、innerFunc
関数がx
変数にアクセスできるため、クロージャは、関数が終了した後に変数の値を保持するための有用な手段です。
ループ変数
編集ループ変数は、プログラムのループ(反復処理)中に使用される変数で、反復ごとに値が更新されます。ループ変数は、通常、反復回数を制御するために使用されます。
以下に、いくつかの言語でのループ変数の例を示します。
C言語
編集for (int i = 0; i < 10; i++) { printf("%d ", i); }
この例では、i
がループ変数です。i
は0から始まり、i
が10未満の場合にループが続き、ループごとにi
の値が1ずつ増加します。printf
関数は、i
の値を表示します。
Java
編集for (int i = 0; i < 10; i++) { System.out.print(i + " "); }
この例では、C言語と同様にi
がループ変数です。System.out.print
メソッドは、i
の値を表示します。
JavaScript
編集for (let i = 0; i < 10; i++) { console.log(i); }
この例では、i
がループ変数であり、let
キーワードで宣言されています。console.log
メソッドは、i
の値を表示します。
Ruby
編集for i in 0..9 puts i end
この例では、i
がループ変数であり、0..9
範囲オブジェクトを使用して、i
の値を0から9まで反復します。puts
メソッドは、i
の値を表示します。
型推論
編集型推論は、コンパイラがコードを解析して、変数の型を自動的に推測する機能です。 変数の宣言時に型を指定する必要がなく、簡潔なコードを書くことができます。
以下に、いくつかの言語での型推論の例を示します。
C++
編集C++では、auto
キーワードを使用して型推論を行うことができます。auto
を使用することで、コンパイラが変数の初期値から型を推論します。
- auto
auto x = 10; // xはint型に推論される auto y = 3.14; // yはdouble型に推論される
また、decltype
キーワードを使用して、式から型を推論することもできます。
- decltype
int x = 10; decltype(x) y = x; // yはint型に推論される
Java
編集Java 10以降では、var
キーワードを使用して型推論を行うことができます。
var x = 10; // xはint型に推論される var y = 3.14; // yはdouble型に推論される
Rust
編集Rustでは、特別なキーワードはなく、「: 型」を省略すると型推論が行われます。
let x = 10; // xはi32型に推論される let y = 3.14; // yはf64型に推論される
Go
編集Goには2つの型推論方法があります。
varキーワードを使った型推論
編集Goでは、var
キーワードを使って変数を宣言するときに、「: 型」を省略すると型推論が行われます。例えば、以下のように書くことができます。
var x = 10 // xはint型と推論される var y = "hello" // yはstring型と推論される
:= 構文を使った型推論
編集Goでは、:=構文を使って変数を宣言し、コンパイラに型を推論させることもできます。:=構文はvarキーワードを省略することができます。例えば、以下のように書くことができます。
x := 10 // xはint型と推論される y := "hello" // yはstring型と推論される
このように、Goでは簡単に型推論を行うことができます。
Julia
編集Juliaでは、変数の宣言時に型を指定しなくても、初期値から型を推論することができます。
x = 10 # xはInt64型に推論される y = 3.14 # yはFloat64型に推論される
C#
編集C#における型推論は、varキーワードを使用します。このキーワードは、変数を宣言するときに使用される型名の代わりに、コンパイラが変数の型を自動的に推論します。変数に代入された値の型に基づいて、コンパイラは変数の型を決定します。例えば、以下のコードでは、numにint型が自動的に割り当てられます。
var num = 10;
Scala
編集Scalaにおける型推論は、コンパイラが自動的に変数の型を決定することで実現されます。変数を宣言するときに型を指定する必要がなく、コンパイラが式の型を解析して変数の型を決定します。例えば、以下のコードでは、messageにString型が自動的に割り当てられます。
val message = "Hello world!"
Kotlin
編集Kotlinにおける型推論は、変数を宣言するときにvarまたはvalキーワードを使用し、型名を省略することで実現されます。コンパイラは式から変数の型を推論し、必要に応じて暗黙的な型変換を実行します。例えば、以下のコードでは、numberにInt型が自動的に割り当てられます。
var number = 42
型ヒント
編集型ヒントとは、プログラム中の変数や関数の引数などに明示的に型情報を付与することです。動的型付け言語で使用されます。
以下にPythonとTypeScriptの例を示します。
Python
編集# 変数の型ヒント age: int = 25 name: str = "John" # 関数の引数と戻り値の型ヒント def add(a: int, b: int) -> int: return a + b
上記の例では、変数age
にint型、変数name
にstr型をアノテーションしています。また、add
関数の引数a
とb
にint型を、戻り値にint型をアノテーションしています。
TypeScript
編集// 変数の型ヒント let age: number = 25; let name: string = "John"; // 関数の引数と戻り値の型ヒント function add(a: number, b: number): number { return a + b; }
上記の例では、変数age
にnumber型、変数name
にstring型をアノテーションしています。また、add
関数の引数a
とb
にnumber型を、戻り値にnumber型をアノテーションしています。
Clojure
編集Clojure は動的型付け言語であり、静的な型チェックは提供していません。しかし、Clojure 1.9 以降では、型ヒントを使用して変数に型情報を提供することができます。
型ヒントを使用するには、変数宣言に ^
を付けて型アノテーションを記述します。例えば、整数型の変数 x
を定義する場合、以下のように書くことができます。
(def ^Integer x 10)
同様に、文字列型の変数 s
を定義する場合、以下のように書くことができます。
(def ^String s "hello")
型ヒントは、Clojure の REPL などで評価される式に対しても使用できます。例えば、以下のように数値を足し合わせる関数を定義する場合、引数の型を指定することができます。
(defn ^Integer add [^Integer x ^Integer y] (+ x y))
このように、Clojure では型ヒントを使用して、コンパイラに型情報を提供することができます。ただし、実行時には引数の型が変更される可能性があるため、注意が必要です。