前回はコンパイルエラーとその対処法について解説しました。
前回の記事:
今回の記事ではC#の文法についてみていきましょう!
プログラミングにおいて最重要な変数と型についてしっかり解説しています。
型については、初心者さんはいきなり全部を理解しようと思うと挫折すると思います。
型の解説からはある程度Unity C#に慣れながら理解していけばOKです。
変数とは
変数とはアプリケーション上のデータ、値を表すものになります。
変数の宣言と変数の初期化
それでは変数の使い方について解説していきたいと思います。
変数を使用する際には必ず、変数の宣言、もしくは初期化を行う必要があります。
変数の宣言の書き方は二つに分かれます(コードではなく日本語で書くと以下の形)。
- 変数の宣言の場合:<型名> <変数名>;
- 変数の宣言+初期化の場合:<型名> <変数名> = <初期値>;
前者では、 型が<型名>で名前が<変数名>という変数があることを宣言しています。
後者では、/型が<型名>で名前が<変数名>という変数があることを宣言して、<初期値>を値として設定しています。
最後の;(セミコロン)
は忘れないようにして下さい。忘れますとコンパイルエラーが発生します。
変数の使い方の例
それでは実際にスクリプト上で変数がどのように使われているのか見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using UnityEngine; class UnityClass : MonoBehaviour { // 変数を使ってみる(宣言の仕方) void Init() { //OK ケース var a = 10; // aという名前の変数を定義しています var _1 = “enjoy”; // 変数の名前の先頭文字はアルファベットか’_’だけ var b2 = 20; // 数字は2つ目の文字以降ならOK // NGケース var 11 = 10; // <- 数字から始まる名前はダメ var *{ = “”; // <- アルファベットと数字、’_’以外の文字は使用できない } } |
ソースコード上の至る所にvar
から始まる行が見受けられると思いますが、その部分が変数を宣言または初期化している部分になります。
var
は上で説明した型名の部分に当てはまります。
- 変数の宣言:<型名> <変数名>;
- 変数の初期化:<型名> <変数名> = <初期値>;
var
の後にa
や_1
、b2
などが続いていますが、その部分が変数名となります。つまり、上のサンプルコードでは「a」と「_1」、「b2」といった3つの変数が存在しています。
変数名について
変数名は頭文字がアルファベットまたは_
で始まり、その後にアルファベットまたは数字、_
が続く文字列(ワード、テキスト)にする必要があります。
そのため、サンプルコードの中にあるNGケースとして、11
や*{
といった変数名はつけることができません。11
は頭文字が数値から始まっており、*{
は使用できる文字以外のものが使われているので、このような変数名がある時はC#コンパイラーはコンパイルエラーとして扱います。
また、C#が使用しているキーワード(using
やvar
などの単語)はそのまま変数名には使用できません(※)。
※一応回避策がC#では用意されていて、変数名にキーワードを使用したいときは、@
を先頭につけることで使用できます。が、特に理由がない限り使用しないようにしましょう。
var @using = 10;
var @var = 12;
varキーワードについて(型推論)
少し手順が前後するのですが、変数の型について説明する前に先にvar
キーワードについて解説します。
var
キーワードは変数の初期化の時に使用できるキーワードで、変数の型名を省略することができます。
その際、初期値の内容から変数の型をC#コンパイラーが推測して自動的に設定してくれます。この機能のことをプログラミングの世界では型推論と呼ばれています。
そのため変数の初期化の時にだけしか使うことができません。また、まだ解説しておりませんがメンバ変数の宣言にも使用できません。
1 |
var Apple; // <- NG |
変数の型とまだ解説していないものがでてきて困惑されると思いますが、変数の型はプログラミングの世界において重要な意味合いを持つものになりますので、しっかり理解していただきたい要素になります。
この後すぐに追加の説明をしていきますが、今は変数には型というものが必要で、型名を省略したい時はvar
が使える場合があると覚えてください。
変数の型とは (やや高度な内容も含むので焦らずに)
変数の型とは「変数がどのようなものか」を説明するためのものです。
C#では変数を使用する時はどこかでその変数の型を指定する必要があります。このことを専門用語で静的型付け言語と言います。(プログラミング言語の中には型を書く必要がないものがありますが、それはC#でいうところのvar
を毎回使用していることと同じ意味になります。)
そのため変数を使用する際にはC#にはどのような型があるのかを必ず知っている必要がありますので、それについて説明していきます。
変数の型には次の種類があります。
- C#が提供している基本型
- 基本型を組み合わせてできたclass型やstruct型
C#で使用できる変数の型について
C#の型は大きく分けて基本型(Build-in Type、組み込み型)とユーザー定義型の二つの種類に分類されます。
基本型はC#が提供している型の最小構成単位になります。基本型はそれ以上分割できません。
その反対にユーザー定義型は基本型を組み合わせた型になります。
また、型は値型と参照型にも大きく分類されます。
値型と参照型の違いにつきましては参照型のところで説明していますのでそちらを参照して下さい。
C#の値型に分類される基本型には主に次のものがあります。
- int: 整数型
- float: 浮動小数点型(実数)
- char: 文字型
- bool: 論理型
- uint: 符号なし整数型(正の数のみ)
- byte: 符号なし整数型(正の数のみ)
- double: 浮動小数点型(実数)
- decimal: 浮動小数点型(実数)
- enum型:System.Enumクラスを継承した型。値型として扱われる。
- struct型:classとして扱える値型
C#の参照型に分類される基本型には主に次のものがあります。また、クラスとして定義されたユーザー定義型はすべて参照型として扱われます。
- string:文字列型
- object:オブジェクト型
- dynamic:実行時型チェック型(Unityでは使用できません。)
- ポインタ型:メモリへのアドレスを表す型。複数ある。
- delegate・event型:メソッドをデータとして扱える型
整数型
整数型は整数を表す基本型で次のものがC#では定義されています。byte、sbyte型のサイズである8ビットを最小サイズとして、その倍数のビット数を持ちます。
【符号つき整数型(正と負の数を表現できる整数型)】
- sbyte: 8ビット数の整数型。-2の7乗から2の7乗-1までの範囲を取る。
- short:16ビット数の整数型。-2の15乗から2の15乗-1までの範囲を取る。
- int:32ビット数の整数型。-2の31乗から2の31乗-1までの範囲を取る。
- long:64ビット数の整数型。-2の63乗から2の63乗-1までの範囲を取る。
【符号なし整数型(正の数のみ表現できる整数型)】
- byte: 8ビット数の整数型。0から2の8乗-1までの範囲を取る。
- ushort:16ビット数の整数型。0から2の16乗-1までの範囲を取る。
- uint:32ビット数の整数型。0から2の32乗-1までの範囲を取る。
- ulong:64ビット数の整数型。0から2の64乗-1までの範囲を取る。
なお、プログラミングの世界では値が取れる範囲に制限があり、これはコンピュータのハードウェア側の都合によるものです。また、値の範囲の限界は基本的に2の乗数をとりますが、こちらもハードウェアによるものになります。
また、符号ありなしといった負の数を取るか取らないかでも型分けされています。
プログラミングでは整数を表す時にはint型がよく利用されていますので、基本的にはint型で大丈夫でしょう。
また、longを超えるようなとてつもなく大きい数値を扱いたいときはUnityでは BigInteger型が用意されています(実際にBigIntegerを使ってゲームを作っている記事はこちら)。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int i1 = 10; short s1 = 23; long l1 = 20l; //末尾にlをつけるとlong型として認識される。 uint u1 = 234u; //末尾にuをつけるとuint型かulong型として認識される。 byte b1 = 34; byte b2 = 1000; // <- エラー。byte型の値の範囲を超えている。 byte b3 = (byte)1000; // キャストと呼ばれる型変換機能を使うと問題なし。 //2進数、16進数表記 int b = 0b1000_0001; // 初めに'0b'、'0B'をつけると2進数表記になる。`_`は0bの後ならどこに書いてもいい int x = 0xFF12AB; // 初めに'0x'、'0X'をつけると16進数表記になる。 |
ビット数(bit)とバイト(byte)について
整数型の説明でビット数という単語が出てきました。ビット数(bit)はコンピュータのメモリ上のサイズを表す単位になります。
また、8ビットで1バイト(byte)になります。バイトのサイズは2の乗数単位に区切られています。
現在のコンピュータでは8ビットを最小データサイズとして扱われることが多いです。
ビット数はアセンブリ(機械語)などのコンピュータそのものを扱う時に重要になるものになります。
現在ではあまりビット数を意識する必要はないのですが、C#が参考にしたC言語というプログラミング言語はアセンブリ寄りのコンピュータに寄り添った言語として昔から広く使われています。
コンピュータが生まれて間もない時にはアセンブリやC言語しかありませんでした。
アセンブリやC言語を用いたアプリケーション開発はコンピュータの仕組みや都合に合わせて実装する必要があったため、難解な技術が要求され、バグが生まれやすいものでした。
それらの反省を踏まえて、C#やJava、Ruby、Python、Golang、Swiftなど近年製作されたプログラミング言語の大半は人が使いやすくアプリケーションを簡単に製作できるように設計されています。
2進数、16進数表記について
2進数、16進数は数値を2進数では0か1、16進数では0-9、A-F(a-f)で表す数の書き方になります。16進数のアルファベットは大文字、小文字のどちらでも問題はありません。
これらの書き方はコンピュータ上のデータを直接表現するものになります。
また、ビット演算を行う時際には2進数、16進数の方が見やすいためよく使われています。詳しくはビット演算の解説と合わせて行いたいと思います。
浮動小数点型
浮動小数点型は実数(小数点を含む数)を表す基本型で、次のものがC#では定義されています。
【浮動小数点型】
- float: 32ビット数の整数型。C#上では末尾に
f
をつけるとfloat型として扱われます。 - double:64ビット数の整数型。C#上では通常の実数がdouble型として扱われます。
- decimal:128ビット数の整数型。C#上では末尾に
m
をつけるとdecimal型として扱われます。
浮動小数点型にも整数型と同じく値が取れる範囲に制限があり、またビット数が小さいものになる程計算精度の問題が大きくなります。(こちらもコンピュータ側の都合によるものです。)
また、浮動小数点型は実数をコンピュータ上で表現するための一つの方法になり、割り当てられたビット数を次の要素に分割しています。
- 正負を表す符号部
- 指数の値を表す指数部
- 値を表す値部
基本的にビット数が大きいほど、指数部と値部が大きく割り当てられており計算精度の問題が小さくなります。
プログラミングの世界における実数の計算には計算誤差の問題がまとわりつくものですが、日常生活範囲の用途での計算ではfloat型を使用することで十分信頼できる計算結果が得られます。基本的にはfloat型を使いましょう。
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 |
//float型は末尾にfをつける float f1 = 123.456f; float f2 = 123f; float f3 = 123.f; // <- NG float f4 = -1.234f; float f5 = 0.246f; float F1 = 10e10f; // <- 指数表記。1の10乗を表す float F2 = 10e-10f; // <- 指数表記。1の-10乗を表す //double型には末尾に何も書かない double d1 = 1.23; double d2 = 123; double d3 = 1.; // <- NG double d4 = -1.234; double d5 = 0.246; double D1 = 10e10; //指数表記。 double D2 = 10e-10; //decimal型の末尾にはmをつける decimal m1 = 1.23m; decimal m2 = 123m; decimal m3 = 1.m; // <- NG decimal m4 = -1.234m; decimal m5 = 0.246m; decimal M1 = 10e10m; //指数表記。 decimal M2 = 10e-10m; |
文字型、文字列型
文字型、文字列型はその名の通り、文字や文章、テキストを表す基本型になります。
- char型:文字型。一文字を表す。characterという英単語を省略したものになります。
- string型:文字列型。文章やテキストを表す。複数のchar型の変数の並びになります。
これらの型もコンピュータから見ると数値として扱われています。
数値のままだとどの文字を表しているのかわからないため、コンピュータの世界では文字コードという数値と文字の対応表を使って文字、文章を表現しています。
C#での標準文字コードはUnicodeの一種であるUTF-16になります。
プログラミング言語によって標準の文字コードが異なっていますが、近年ではUTF-8が広く利用されています。(UTF-8もUnicodeの一種であります。)
余談ですが、今後文字コード間の変換が必要になる時が出てくるかもしれませんが、その時はC#の標準ライブラリを利用しましょう。
文字の書き方
文字の書き方およびchar型の設定方法は下の通りです。
- 文字の書き方:
'<一文字>'
- char型の書き方:
char <変数名> = '<一文字>';
'
はクォーテーションと呼び、文字型を表すときは'
で1文字を括って下さい。(初めてこの文字を見た方には入力の仕方がわからないと思いますが、一般的なキーボードには対応するキーが存在していますので探してみて下さい。筆者のキーボードではShiftを押しながら7キーを押すと入力できます。)
基本的に文字はキーボードなどから入力したものをそのまま使用できますが、改行やタブなど一部の文字にはそもそも文字が割り当てられていません。そのような特殊な文字に対応するためプログラミング言語および文字コードにはエスケープシーケンスと呼ばれる書き方が存在しています。
エスケープシーケンスの書き方は先頭に\
を付けた後に対応する文字を続けます。具体的には下の通りです。
\<文字>
これだけではイメージし辛いので次にエスケープシーケンスの一部をリストアップします。
- \n:改行文字
- \r:行頭に戻る
- \t:水平タブ
- \v:垂直タブ
- \b:ブザー
- \u:Unicode文字の文字コード。Unicode文字を表す文字コードを16進数の4文字を続ける。
- \x:UTF-16の文字コード。Unicode文字を表す文字コードを16進数の4文字を続ける。
文字列の書き方
文字列の書き方およびstring型の設定方法は下の通りです。
- 文字列の書き方:
”<文字>..."
- char型の書き方:
string <変数名> = "<文字>...";
"
はダブルクォーテーションと呼び、文字型を表すときは"
で1文字を括って下さい。(筆者のキーボードではShiftを押しながら2キーを押すと入力できます。)
文字列の中には複数の文字を入力することができます。文字として扱えるものは文字列の中でも使用することが可能となっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
char ch1 = 'A'; // ''(クォーテーションで一文字を括る) // '\'で始まる一文字をエスケープシーケンスと呼び、 // 改行など単純な文字では表せないものを表現する時に使用する char ch2 = '\n'; // <- 改行文字 char ch3 = '\t'; // <- タブ文字 char ch4 = '\\'; // <- \ char ch5 = '\0'; // <- ヌル文字。何も表していない文字。 string str1 = "ABC"; // ""(文字列はダブルクォーテーションで括る) string str2 = "ABC\n"; //エスケープシーケンスも含めることができる。 // str3にはabcdefghiが設定される。 string str3 = "abc" + "def" + "ghi"; |
また、文字列には下の特殊な書き方が存在しています。
- @”<文字>…” : 入力した文字列そのまま使用したい時に使用する。
- $”<文字>…” : 書式(Format)付き文字列。変数を文字列の中で使用したい時に使用する。
@”<文字>…”
@"<文字>..."
を使用することで<文字>...
の中に入力したものをそのまま文字列として表現できます。
通常の文字列の中にエスケープシーケンスの文字(例えば\n
)をそのまま書きたい時は\\n
と\
をエスケープする必要がありますが、@"<文字>..."
の中だと\n
と入力するだけでよくなります。
ファイルパスを直接書きたい時などに使用すると便利な書き方になります。
1 2 3 |
//下のものは同じ文字列になります。 string filename1 = @"c:\documents\files\u0066.txt"; string filename2 = "c:\\documents\\files\\u0066.txt"; |
$”<文字>…”
$"<文字>..."
を使用することで<文字>...
の中に変数を埋め込むことができます。
変数の埋め込み方は{変数名}
と{
と}
で変数名を括ります。
また{変数名:<書式>}
と書くことで、変数の値を文字列に変換する方法を指定することができるようになります。このような機能を書式(Format、フォーマット)と呼ばれています。
書式の書き方は変数の型によって異なりますので、随時調べてみて下さい。
こちらも手軽に変数を文字列に変換することができるので、C#のとても便利な機能になっています。
1 2 3 4 5 6 7 8 9 |
//下のものは同じ文字列になります。 int n = 100; string str1 = $"n = {n}"; string str2 = "n = 100"; //変数を文字列に変換する方法(書式)も指定することもできます。 //書式につきましては型によって書き方が異なります。 var date = DateTime.Now; string str3 = $"Today = {date:MM:DD}"; //今日の日付(4/1など)がテキストとして表示される |
論理型
論理型は1か0またはtrue(真)かfalse(偽)を表す型になります。
論理型はアプリの状態を表すフラグとして使用されたり、条件式などアプリの処理を分岐させる部分で使用されています。
1 2 3 4 5 6 7 |
bool b1 = true; bool b2 = false; bool b3 = b1 || b2; // <- or論理演算子を使ってb3に値を設定している。 if(b3) { // if(条件式)というように使うことが多い //... } |
参照型
参照型はデータそのものを表すのではなく、使用しているデータの位置を表す型になります。
そのため参照型の変数自体にはデータの実体はなく、C#が裏で自動的に参照型が指し示すデータを確保しています。
そのため参照型のサイズは見かけ上全て同じになりますが、それは使用しているデータの場所を表しているためで、実際のデータのサイズは型の定義内容によって異なります。
これはC言語のポインタという機能に近いものですが、C#では一般的にポインタを意識することはありません。ポインタの利用は危険性があり、バグの原因になりやすいものです。
そのためC#ではポインタを直接使用するより安全に参照を活用できるように改良が加えられています。
C#を使用する上で参照型を意識することはあまりないですが、この参照型の性質について理解をしていないと不可解な動作にしか見えない部分がC#には存在していますので、こういうものがC#の裏側にはあることは覚えておくといいでしょう。(特にメソッド周りを理解する時に助かります。)
参照型として扱われる型は次のものがあります。
- 全てのclass型
- object型
- dynamic型(※Unityでは使うことができません。)
- string型
- delegate型
- event型
また、これまで紹介してきたstring型以外の基本型は全て値型としてC#では定義されています。値型の変数は直接データを表しています。
この参照型と値型の違いを理解していると、今後説明するメソッドの引数の受け渡し周りの理解を捗らせることでしょう。
下のサンプルコードは参照型の一例になります。中で型変換というC#の機能を使用しています。
型変換については後ほどこの記事で説明していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Sample { public void XXX() {} public int Value = 100; } //全てのclassは参照型になる Sample sample = new Sample(); Sample sample2 = new Sample2(); //参照先のデータが持っているものを呼び出す一例 sample.XXX(); // <- sampleが指し示しているデータのXXXメソッドを呼び出す。 sample.Value = 200; // <- sampleが指し示しているデータのValueフィールドに値を設定している。 sample2.XXX(); // <- こちらはsample2が差しているデータになる。 sample2.Value = -100; // <- 上と同じ // object型には全ての変数、型のデータを記録しておくことができる。 object obj1 = new Sample(); object obj2 = 100; // <- int型をobj2に格納する //参照先のデータが持っているものを呼び出す一例 obj1.XXX(); //<- NG 型が特定されていないのでできない。 ((Sample)obj1).XXX(); // <- OK 型変換を行った後ならOK ((Sample)obj2).XXX(); // <- NG 関連性がない型には型変換は行えないので実行時エラーになる。 |
ポインタ型
参照型に似たものなのでポインタ型についてもここで触れておきます。
C#にもC言語でいうポインタ型が存在しますが、通常積極的には使用しません。
C#にはunsafeなコードというものがあり、その中ではC言語のようにプログラミングを行えるようになっています。ポインタはその中で利用できます。
また、DLL(動的リンクライブラリ)を利用する時にも使用されます。こちらはunsafeではなくても利用できます。
以上から、直接アセンブリやメモリ操作を行いたいときやアプリ外の機能を利用したい時に使用されるものとなります。
struct型
struct型はclass型のように使用できますが、値型として扱われます。
構造体とも呼ばれます。
使い方としてはこの両者に一見違いはないですが、class型にはできるのにstruct型にはできないことがいくつか存在します。
また、値型と参照型の違いを利用したアプリ実装も存在しています。
一般的なアプリ開発ではclass型の方を使用するだけで十分となります。
enum型
enum型は列挙型ともいい、アプリ上で固定値やフラグとして使用したいものを複数まとめて定義したい時に利用されます。
enum型は値型として扱われます。
enum型として定義されたものにはC#側で自動的に値が割り当てられ、int型に型変換することができます。また、こちらから自由な値を指定することも可能です。
別の記事で説明するswitch文などを用いた条件分岐に利用されることが多いです。
直接数字を扱わないことでコードの可読性を高めています(急に出てくるよくわからない数値はマジックナンバーと呼ばれ、プログラムの理解を妨げます)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//enum型の定義 enum Fruits { Apple, // <- 0 初めの値は0 Banana, // <- 1 ひとつ前の連番値が設定される Orange = 100, // <- 自由な値を設定 Grape, // <- 101 ひとつ前の連番値が設定される } Fruits fruits = Fruits.Apple; // fruitsに設定された値によって処理を分岐するコード // switch文については他の部分で解説します。 switch(fruits) { case Apple: //... Appleの時の処理 case Banana: //... Bananaの時の処理 case Orange: //... Orangeの時の処理 case Grape: //... Grapeの時の処理 } |
delegate型・event型
delegate型およびevent型はメソッドを値・データとして扱うために使用される型になります。
メソッドを値として扱えて何かメリットがあるのかと思われますが、GUIアプリケーションや皆さんが現在見ているブラウザにもたくさん使われている重要なプログラミングの機能になっています。
delegate型とevent型についてはまた別の記事にて解説しますが、以下に簡単な使用例を挙げておきます。
今はdelegate型・event型があることだけ覚えておけば十分です。
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 |
// SampleDelegateという名前のデリゲート型を宣言する delegate void SampleDelegate(int i); void Method(int i) { i += 10; } // SampleDelegate型のcallback1という変数名で宣言する // callback1には何も設定されていない。 SampleDelegate callback1; // SampleDelegate型のcallback2をMethodで初期化する // Invokeメソッドでdelegateに設定されたメソッドを実行することができる SampleDelegate callback2 = Method; callback2.Invoke(100); // <- Methodメソッドが実行される。 // event型の使い方 // event型はdelegate型を簡単に使えるようにしたもの class Sample { public event SampleDelegate Event1; //event型はクラス内でしかInvokeメソッドを呼び出すことができない public void CallEvent(int i) { Event1.Invoke(i); } } var sample = new Sample; //event型へメソッドを追加・削除することはクラス外でもできる sample.Event1 += Method; // Event1にMethodを追加する sample.CallEvent(111); //event型はクラス内でしかInvokeメソッドを呼び出すことができないので、メンバメソッド経由で呼び出している。 sample.Event1 -= Method; // Event1に設定されていたらMethodを削除する |
型変換(キャスト、Cast)について
型変換(キャスト、Cast)とは型を変換することになります。プログラミング中に使用している型を他の型に変換したい場合に使用します。
書き方は次のようになります。変換したい値・変数の前に、括弧で括った変換先の型の名前を書くだけです。
(<型名>
)<値または変数>
型変換の原則として、変換元の型と関連がある型にしか変換できません。
基本的に数値型同士の変換、継承関係のあるclass型やstruct型なら型変換が可能になります(継承に関しては今はわからなくてOKです)。
C#では静的型付け言語なので型変換ができないものを変換したときはコンパイルエラーになります。
ですが、object型やdynamic型などを使用した時はコンパイラーによるエラー検査が行うことができず、アプリを実行するまでエラーが発生しません。
そのようなコードを含んでいる場合、その箇所を実行した時は型の互換性のないものへ無理やり変換したとみなされアプリの実行時エラーとして例外が発生します。
一応、コードを注意深く読むことで発見することはできるのですが、コードを深く読む熟練の技術が必要になるので、基本的にobject型やdynamic型を使うことは避けましょう!
1 2 3 4 5 6 7 8 9 10 11 12 |
int a = 10; float b = (int)a; //float型に変換する class A {} class B {} A class1 = new A(); B class2 = (B)class1; // <- NG 型に関連性がない class C : A {} // CはAを継承している C class3 = new C(); A OK = (A)class3; // <- OK AとCには関係性があるので変換できる。 |
文字列型と他の型の相互変換について
型変換に因んで、全ての型はToString()
メソッドを使用することで文字列型(string)に変換することができます。
先に$"..."
で変数を文字列に変換することができると説明しましたが、その裏側でこのToString()が使用されています。
ToString()
では数値などの値型はその値が直接文字列に変換されます。
class型などの場合はその型名が文字列に変換されますが、それはclass型などはその内容が型によって異なるためコンパイラーが自動的に決定することが難しいためです。
型名以外の文字列に変換したいことはよくあるので、C#ではToString()
メソッドをオーバーライド(※)するとこちらで決めた文字列に変換することができます。
またもちろん、ToString()でも書式(フォーマット、Format)を指定することができます。
※メソッドのオーバーライドはクラスの継承と関係があるC#の機能になります。
その反対の文字列から他の型に変換する際は、自作するかC#の標準ライブラリを使用する必要がありますが、それらには値型など簡単な型への変換処理しか用意されていません。
より高機能で簡単に文字列と型の相互変換を行いたい時は次に説明するシリアライズ機能を利用して下さい。
1 2 3 4 5 6 7 |
int a = 100; string str = a.ToString(); // <- 文字列に変換される string str2 = $"{a}"; // こちらでもOK //書式を指定した変換 string str3 = a.ToString("X"); //16進数表記で文字列に変換 string str4 = $"{a:X}"; //こちらでもOK |
余談:シリアライズ(Serialze)について
文字列への変換にはToString()
以外にシリアライズ(Serialize)と呼ばれるデータを文字列に変換する処理も存在します。
サーバー間通信などアプリの間でデータの受け渡しを行う際にはシリアライズを利用するととても便利なため、C#やUnityではあらかじめ標準ライブラリとして提供されています。
シリアライズの際にはどのように型の内容を文字列として表現するか決める必要があるのですが、それについては既に色々な形式が考案されています。代表的なものとしてはXMLやJSON形式などがあります。UnityではJSON形式やYAML形式などが使われています。
ちなみにシリアライズしたものをもとのデータに変換することをデシリアライズ(Deserialize)と呼ばれています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//まだ説明していないものが多いですが、必要になるので書いてます。 using UnityEngine; [Serializable] class MyClass { public int Value = 100; } var myClass = new MyClass(); string jsonText = JsonUtility.ToJson(myClass); // <- シリアライズ //copyDataにはシリアライズされた部分のデータが格納される。データの中身はmyClassと一致する var copyData = (MyClass)JsonUtility.FromJson<>(jsonText); // <- デシリアライズ |
実際に変数をUnityで使ってみよう
変数の型について長く説明してきました。まだまだ型についての注意点、性質などがあるほどプログラミングの世界で「型」は重要です。
が、ここでは一旦この程度で解説を区切り、実際にUnity上で変数を使っていきます。
以前の記事で既に変数は使用していますが、変数について何も知らなかった時と、変数について知った後で、ソースコードの見え方が変わったかと思います。
スクリプトの作り方がまだわからない方は以前の記事を参照してください。
また、GameObjectにアタッチする時はファイル名と中のクラス名を一致させないといけないので注意して下さい。
以下のサンプルコードをそのまま使用する時はclass Sample : MonoBehaviour
と書かれた行のclass名がSample
になっているので、ファイル名をSample.cs
としてください。
変数の型について長々と説明しましたが、サンプルコードにはまだ解説していないC#の構文があります。
と言っても算数の足し算的なものなので気にせず書いてみましょう。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sample : MonoBehaviour { // float型のValueという変数名のメンバ変数を0.1で初期化している public float Value = 0.1f; // Color型のColorという変数名のメンバ変数をColor.whiteで初期化している // ちなみにColorはstruct型 public Color Color = Color.white; // MeshRenderer型のMeshという変数名のメンバ変数を宣言している // ちなみにMeshRendererはclass型 public MeshRenderer Mesh; // Start is called before the first frame update void Start() { // 箱の色を変えるコード // メンバ変数であるMeshのmaterialメンバ変数のcolorプロパティにColorメンバ変数の値を設定する // Mesh.materialメンバ変数はUnityEngine.Material型 // Mesh.material.colorプロパティはColor型 // Mesh.material.colorとColorは同じ型なので値が設定できる。 Mesh.material.color = Color; // Mesh.material.colorプロパティはColor型 // 100はint型 // Mesh.material.colorと100は関連性がない型なので値は設定できず、コンパイルエラーとなる Mesh.material.color = 100: // <- NG コメントアウトして下さい } // Update is called once per frame void Update() { // transformメンバ変数のpositionプロパティにVector3型の値を足し合わせる。 // transformはTransform型 // transform.positionプロパティはVector3型 // new Vector3(Value, 0, 0)はVector3型 // transform.positionとnew Vector3(Value, 0, 0)は同じ型なので値が設定できる。 transform.position += new Vector3(Value, 0, 0); // 型変換の一例 // transform.positionプロパティはVector3型 // new Vector2(0, Value)はVector2型 // transform.positionとnew Vector2(0, Value)は異なる型だが、型変換が可能なので値が設定できる。 transform.position += new Vector2(0, Value); // <- OK こちらは実行できるコードなので、このままでいい } } |
まとめ
かなり解説が長くなってしまいましたが、この記事をまとめると次のようになります。
- C#には変数というものがある
- 変数を使う前には変数の宣言または変数の初期化を行う必要がある
- 変数の宣言と初期化には、変数の型と名前が最低限必要になってくる
- varキーワードを使うと変数の型を省略することができるが、変数の初期化の時だけ使える。
- 型には基本型(Build-in Type)とユーザー定義型がある。
- 基本型はC#が提供している型で全て数値を表す。
- class型とstruct型は基本型を組み合わせてできた型。
- 型には値型と参照型の2種類ある。
- 値型は変数自体に値が格納される型。
- 基本として、整数を使いたい場合はint, 実数を使いたい場合はfloat, 文字列を使いたい場合はstring
- 参照型はデータの場所についての情報が変数に格納され、実際のデータはC#側で管理される。
- 「型」はプログラミングの世界ではとても重要なものでかつ奥が深いもの。
それでは、次の記事に行ってみましょう。
次の記事:
コメント