物理シミュレーションを"win環境"でやる案件を投げられた筆者がUnityを初めて使うことを決心し, C#の速習を始めた一連の備忘録
前回の復習
初心者C#erの筆者が初めてC#書いた. ただ前回はダウンロード方法とか実行方法デバッグ方法の肩慣らし編. 今回から型らしいので快速に行きたい.
それとstudentsアカウントを使ってJetBrainsのRider(これ)を導入してみた.
Visual Studioに何かしらの不満があったわけではないけど無料でもらえると聞いて心が動いた次第.
§2 C#の基本
2.1 変数
2.1.1 変数の宣言
C#初学者的に見るとメモリ管理よろしくガベージコレクションはc系あるのか不安に思えたけどあるっぽい.
すごいモダンだ...
// 基本の形は
// データ型 変数名 [=初期値] [, 連続で宣言できるよ]
// ex.
int data;
int data1, data2;
int num = 108;
string str = "hello world!";
補足
- readableコードな視点から, 変数の連続宣言はやめておいたほうが良いよ
- 初期化と同時に代入もしようね. 初期化のし忘れエラーを吐くリスクがあるよ
- 少なくとも初期化代入の時点でタイプに対応するゼロの値を入れよう(0, '', "", []...)
2.1.2 識別子の命名規則
要するに変数名とか関数名, クラス名...etcに対する命名規則
- 予約語ダメ
- 1文字目はアルファベットかアンダースコア
- 2文字目以降は, 一文字目ルールで使える記号と数字
- アルファベットの大文字小文字は区別
予約語は一般的な範囲. (c.f. C#ref)
ちなみに予約語どうしても使いたいなら, 変数名の前に@を付けることで可能らしい(var @if = XX 的な).
これは他のプログラミング言語との連携とかを考えて作られた方法でverbatim identifier(逐語的識別子)と呼ばれるみたい
あと, 予約語にはコンテキストキーワードとよばれるものがあって, 特定の文脈でのみ予約語として扱われるものだからその文脈以外ではコンテキストキーワードは変数名におけるとか.
ただしいずれにしろ可読性異常に低いからやめよう.
本の中で命名規則に対するベストプラクティスが書いてあった, 曰く
- 名前からデータの内容を類推できる...ok: score, birth / ng: m, n
- 長すぎない, 短すぎない...ok: password, name / ng: pw, RealNameOrHandleName
- 見た目が紛らわしくない...△: tel/Tel, user/usr, record/records
- ローマ字命名はやめよう...ok:name, age / ng: namae, nenrei
- 一文字目アンダースコアは特別な意味を類推させるのでやめよう...ok: price / △: _price
- 決められた記法で統一しよう...mailAddress(キャメルケース)/mail_address(スネークケース)/MailAddress(パスカルケース)
個人的に, 2の長すぎないに関しては冗長なものは良くないけど, 説明的になって長くなるのはいい気もする. どうなんだろ.
3は前にtmpがtemporaryかtemperatureで混乱してた人見たことがある. 多文化交流する現場だと略語もよくないのかも
C#では変数はキャメルケース, クラス/メソッド/プロパティはパスカルケースで画のが慣習らしい.
変数名一つでデバッグのしやすさが一気に変わるから, 多少長くともIDEのご加護があるので詳しく書くことがおすすめかなぁ
c.f. ちなみに変数は値にある意味名前を付けられるという物だからコードをより説明的にさせる使い方もあるよね
string email = "honya@examples.com";
string domain = email.Split('@')[1];
if (domain.Equals("examples.com")) { ...}
こうすることで, 値(email.Split('@')[1])を入れるよりドメイン感が増すし見やすい. こういう説明変数使っていこう.
2.1.4 定数
変数宣言の前にkeyword, "const"を置くだけ.
int price = 1000;
const double Tax = 1.08;
double sum = price * Tax;
実際のコードで, いきなり1.08とか出てきても, 例えば消費税が10%になってしまった世界線の人から見てしまうとわかりにくい.
説明変数の延長で, Taxって振ったほうがいいけれど, この値は定数=不変なので定数情報にしてしまう
そんなイメージかな?
まぁ, 何より消費税あがちゃったら, コードに1.08って書いた分1.1に値を入れ替えないといけないから, 変数にして一括管理したほうが便利.
2.2 データ型
ようやく本題. 組み込み型とユーザ定義型, 値型と参照型で分けられる. ちょうどこんなかんじ
組み込み型 | ユーザー定義型 | |
---|---|---|
値型 | プリミティブ | 構造体 / 列挙型 |
参照型 | string/object | クラス/インターフェイス/デリゲート |
- 組み込み型は言語仕様として存在するもの, ユーザー定義型はライブラリなり自分で定義するもの
- 値型は変数が値そのものを格納するもの, 参照型は変数が値を保持するメモリのアドレスを持つ
(型の種類の画像を上げようと思ったけれどbad requestをqiitaに吐かれてしまったのでurlおいときます)
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/built-in-types-table
代表的な組み込みを以下で解説
2.2.2 整数型
符号の在りなしで大きく分けて二種類
- sbyte short int long
- byte ushort uint ulong
uシリーズ(符号なし)は, 符号ありシリーズと比べて大きな値を扱える(int:±2_147_483_648, uint:0~4_294_967_295, スタート地点の差)
使うのは基本intでいいよ.
2.2.3 浮動小数点型
float, double, decimalの三種. 違いはbitサイズ(32, 64, 128)
ご存知の通り, 符号, 指数, 仮数で少数を表す浮動小数点型なので, サイズは大きいけどdoubleを使うのがいい.
decimalは128bitも食べるけど有効桁数28~29らしいので金融世界で重宝らしい
2.2.4 文字型
単一の文字を表す. 内部では16bitの符号なし整数と対応付け(utf-16対応なので)
なので**char c = (int)128;**とすると, charでも16bitの数値を格納できる. 可読性(ry
単一文字ではなくて文字列がほしいならstringだよ
2.2.5 boolean
true / falseの2値のみ. コンソールだとTrue/Falseと出るけど, ture/falseとコードには書かないとerror
clangと違って0,1と同値とみなすことはできない.
2.2.6 オブジェクト型
動的型付けみたいな挙動するobject型.
本来, int型で定義したらstring型の値を代入すると怒られるけど, そういった型の制限をうけない
object honya = 10;
honya = true;
honya = 'a';
とかできる.
これでダックタイピングとかに対応するのかな
2.2.7 型推論
intとかdoubleとか打たなくてもvarを使えば勝手に型を割り振ってくれるらしい
var honya = 10; // as integer
var morake = "hello"; // as string
ただしあくまで型を割り振るだけで, 例えばもし上記のコードでhonya = "asdf"とintとして割り振られた変数honyaにstringを代入してしまうとエラーを吐く. jsとかのvarとかとは違う. どちらかというとobjectの方が近そう.
便利な反面, 制約もある
- 初期値は省略不可能
- 複数宣言できない
- フィールド宣言はできない(グローバル変数としては使えない
- コンテキストキーワード(Class varが存在するとそっちを優先)
制約といっても制約らしい制約はないね. フィールド宣言できないくらい?
ちなみに, 明示的な方指定, 暗黙的な方指定, どちらがいいかとMSのドキュメントを見てみるとこんなのが
本曰く, 積極的に使っていいとか. というのもIDEの補助機能向上とかとか.
ネット探してみたりで総合的に見てみると, 割とvar使う使わないはそれぞれの職場とか環境でのコード規約と宗教論争の様子.
個人的にはスクリプト言語勢だから雰囲気でvarを使っていてもいいのかなと思いつつ, でもそれだと静的型付けの意味とかかっこよさとかがないので, 基本varは遣わない方向でいきたい.
2.3 リテラル
久しぶりにこういうプログラミングの本を読んでみると, ふとしたところで躓いたところを思い出す
プログラミング始めて間もないころ, リテラル(値)とクラス(型)の違いがわからなくて悩みまくった記憶が今回はよみがえった
int XXX = 100, とか書かれたらint概念と100概念等価にしか初見じゃみえないじゃん()
しばらくして色々なオブジェクト指向に触れて, なんとなくクラスは値と処理を一緒にしたもの, ととらえることで乗り切った感じだった.
なので, string型とかは, 文字列リテラルと文字列リテラルに対応するメソッド(splitとか)がある, みたいな
全てがオブジェクトの言語とかそれはそれでやはりわかりやすかった.
2.3.1 整数リテラル
10進数, 16進数(0xFF), 02進数(0b100)の三つのリテラルがある. いずれもintとかに代入は可能
c.f. セパレーター
可読性を上げるために, 区切ることができる(12_345...みたいな)
注意点としてParseメソッドのような文字列to数値のメソッドではうまく読み込めない
2.3.2 浮動小数点リテラル
小数点の値記法は二つ. そのまま書く方法(3.14)と, 指数表現(.314e3)
指数表現では, 学生の頃やった有効数字適応時の数字の書き方ににている
要するに, 0.00000173205は, 0.173205 * $10^{-5}$で表せるから, 0.17302*e-5とできるよ
2.3.3 補足: 数値リテラルにおける型サフィックス
プログラム上で平文で書かれた数値のリテラルは, 整数はint, 少数派doubleと自動的にみられるけれど, longとかで表したいときもあるわけで.
そういう時は, サフィックスを値の後に置けばよい. (100l...long型で100を表す
type | suffix | ex |
---|---|---|
long | l,L | 100l |
uint | u,U | 123u |
ulong | ul, UL, Ul, uL | 123ul |
float | f, F | 3.5F |
double | d, D | 3D |
decimal | m, M (moneyから来てる) | 300.5M |
この本の筆者は整数は小文字, 少数で大文字にしてるみたい(大文字小文字は意識されない)
注意点として, 値を型の範囲内におさめること. short num = 65535; はエラーを吐く.
2.3.4 文字リテラル
シングルクォートで囲むと, 一文字だけを表せる文字リテラルになる.
文字自体を示す方法と, 16進数で指定する方法がある.
- 'a'
- '\u3042'
c.f. エスケープシーケンス
2.3.5 文字列リテラル
ダブルクォートでくくられたものは文字列リテラル. 文字列なので一文字以上でも扱える.
逐語的文字列リテラル
エスケープシーケンスを使わずに特殊な文字を扱いたい時, 逐語的文字列リテラルを扱える.
- @""で扱う(objective-cが僕の頭をよぎる
- この中では"を除くすべての文字を\なしに扱える.
- これを使うことで改行\nを含む文字列も扱える
- "を使いたいときは, ""のように, 連続して打ち込むと扱える
式展開
- $""と表せられた文字列の中で書かれた{XXX}は, 式XXXを評価した値が返される
- ex. $"your name is {name}" => nameが補完される
- ex. $"{3+4}" => 7が出力
- この中で{}を文字列として出力したいときは{{というように連続で書く.
逐語的文字リテラルと式展開を同時に扱いたい場合は$@""と書けばいい
長くなりすぎたのでここら辺で一度記事をわけることにする.