はじめに
プログラマー初学の人へ61の質問
言語はC#(とC++)を前提に回答していきます。
ちなみに経験1年未満の新人です。
1. 変数と定数の違いは何ですか?
どちらもメモリ領域に名前をつけたものです。
変数は再代入が可能。
定数は再代入が不可能。
C++だと定数はさらにconstとconstexprに分けられます。
const : 初期化後に値を変更できない変数でRAMのみに配置されます
constexpr : コンパイル時にインライン展開される定数でRAMまたはROMに配置されます
ということでconstは厳密には変数だったりします。
あとHaskellなんかは変数が存在しません。
2. 変数と定数はどのように使い分けますか?
後から変更されないものはすべてできるだけ定数で宣言しましょう。
こうすることで値が変化しないことを明示できるので処理を追いやすくなります。
JavaSctiptではconstを積極的に使うみたいな話です。
3. コメントの書き方はわかりますか?
文法的には// コメント
と/* コメント */
で書けます。
でもマルチラインコメントの方はどこからどこまでがコメント行なのか見難いので忘れていいでしょう。
どんなコメントを残すかは宗教戦争。基本方針はリーダブルコードとかに則って書きます。
4. 四則演算はどのように行いますか?
文法的には+-*/
これらは組み込み型へ定義された演算子です。
自分で演算子をオーバーロードすることも可能です。
また、式木を使うことで演算子を使わずに四則演算ができます。
以下は加算の例。
public int Sum(int x, int y)
{
var paramx = Expression.Parameter(typeof(int));
var paramy = Expression.Parameter(typeof(int));
var sumFunc =
Expression.Lambda<Func<int, int, int>>(
Expression.Add(
paramx,
paramy
), paramx, paramy
)
.Compile();
return sumFunc(x, y);
}
Expression
クラスにはAdd
、Substract
、Multiply
、Divide
メソッドが実装されています。ずるい
5. 演算子、論理式、比較子って何ですか?
-
演算子
オペランド間の演算を定義した記号。4の四則演算やnull演算の?、否定の!など。 -
論理式
AND/OR演算のこと。もしくはBoolean。 -
比較子
比較演算子。オペランドの比較を行う。==, !=, >, <
これら。
6. 三項演算子って何ですか?
Boolean?"true":"false"
という記法で書ける条件分岐の記法です。
if(Boolean) return "true";
return "false";
これと同じです。
7. Integer型とFloat(Double)型の違いは何ですか?
まずJavaの話になりますがint型 != Integer型です。値型とラッパーの参照型という違い。C系列にはないのでint32型とfloat型の違いとして進めます。
どちらも値型でintは整数、floatは浮動小数点を格納できます。
確保するメモリサイズは実装次第だけどintが4バイト、floatが8バイト。
そしてfloatは基本的に使わずdoubleを使います。大抵のハードウェアはfloatを演算するときに内部でdoubleにキャストしてから計算して後で戻しています。
組み込みの特殊な状況ではfloatを使うこともあるらしいです。
--20/03/11 追記
AVX命令だとfloat演算はdoubleより数倍速くなるとか。
あとコンパイラが判断してfloatをdoubleに置き換える最適化を行うこともあるようです。
float型とdouble型
いずれにせよシビアなチューニングを行う場面でない限りdoubleを使ってよさそうです。
8. 分岐処理の構文を教えてください。
if、switch、三項演算子、null演算子。関数型だとパターンマッチもあります。
9. ループ構文を教えてください。
for(変数宣言;終了条件;繰り返し演算)
while(終了条件)
foreach(変数宣言 in コレクション)
do-while
は忘れていいでしょう。
C#だとLINQというコレクション(IEnumarable
)の各要素に対して行うメソッド群があります。これもループ。
そしてすべてのループは再帰関数のシンタックスシュガーです。
10. 配列の構文を教えてください。
<型>[要素数]
またはList<T>
。ArrayListは忘れていいでしょう。
C#のListは片方向連結リストで実装されており、InsertやRemoveメソッドの計算量はO(N)です。つまり可変長配列です。
List<T> クラス
InsertやRemoveを多用する場合は双方向連結リストのLinkedList<T>
を使用する方がパフォーマンスの向上が望めます。
LinkedList<T> クラス
11. ハッシュ(辞書)の構文を教えてください。
KeyValuePair<TKey,TValue>
とそのコレクションであるDictionary<TKey,TValue>
。C#もmapでいいのに。
Dictionary<TKey,TValue> クラス
12. 関数(メソッド)の構文を教えてください。
アクセス修飾子 static修飾子 戻り値の型 関数名(引数)
{
関数本体(具体的な処理)
}
これに継承だと:
がついたりジェネリックだとWhere
でT
を指定したり増えていきます。
13. 関数(メソッド)を使用する利点を教えてください。
むしろ使用しないデメリットを答えた方が早いというか、使わないとまともなプログラムを組めません。
14. 標準出力の方法を教えてください。
標準出力って結構な闇では?
標準入力・標準出力ってなに?
Console.WriteLine("Hello")
。
15. 文字列の連結、検索方法を教えてください。
まずC#のString型はimmutable。なので+
などで結合した場合は新しい文字列オブジェクトが生成されます。そのうえで
var greeting = "Hello" + ", " + "World.";
もしくはStringBuilderを使って
var greeting = new StringBuilder().Append("Hello").Append(", ").Apped("World.").ToString();
違いはStringBuilderはmutableなこと。
文字の検索(というか比較)はJavaとC#でちょっと違います。
str.equal("Hello")
とstr == "Hello"
の違い。
Javaは前者でC#はどっちでもいいです。普通は後者。これはC#の言語仕様でString同士の==
がオーバーロードされているため。参照型同士の==
比較はオブジェクト自体が同一かを判定します。
16. クラスの構文を教えてください。
アクセス修飾子 class クラス名
{
中身
}
アクセス修飾子を省略するとinternalになります。
17. インスタンス変数とは何ですか?
オブジェクトのインスタンスに対して定義された変数です。
18. クラス変数とインスタンス変数の違いは何ですか?
staticおじさんがやってくるぞ。
確保されるメモリ領域が異なります。クラス変数はスタックスタティック領域でインスタンス変数はヒープ領域。
というよりヒープ領域にメモリを確保することがインスタンス化。
19. スタティック領域とは何ですか?
そんなものはない。
あるのはスタック領域。
-- 20/03/11 追記
スタック領域(自動記憶域)とスタティック領域(静的記憶域)は別物です。
プログラムの起動時から終了時まで一貫して割り当てられる領域をスタティック領域と呼びます。
グローバル変数やstaticローカル変数、staticクラスやstatic関数を使用すると割り当てられます。
記憶クラスとスコープ
この人のブログはハードウェア周りについてだいぶ勉強になります。
ヒープとスタック
20. クラスの継承構文を教えてください。
class クラス名 : 継承するクラス名(もしくはインターフェース名)
21. 型キャストはできますか?
C++のキャストは闇なので触れません。
C#はint -> long
などデータの情報量が保証される場合は暗黙キャストが可能です。
その他の場合はキャストするメソッドを呼び出します。
int.Parse("1")
22. 型チェックの構文を教えてください。
typeof
またはis
演算子。
C# の is 演算子と typeof の型判定の挙動の違い
23. 関数(メソッド)の初期値って設定できますか?
ちょっと何いってるかわからないですね。
引数の初期値設定ならint Sum(int x = 0, int y = 0)
のような記法で可能です。
24. インターフェース(objective-cやswiftではプロトコル)とは何ですか?
クラスに対して、あるメソッドを実装することを約束するものです。
25. インターフェース(objective-cやswiftではプロトコル)はどのような局面で使用しますか?
ポリモーフィズムを用いて処理を各クラスに記述したいときなどに使います。
26. クラスの継承をするメリットは何ですか?
具体クラスを継承することはデメリットが大きいです。
基本はインターフェース(抽象)に対して処理を行いましょう。
abstractクラスの継承はインスタンス変数を実装したいときに使います。
Go言語なんかはクラスの継承がないですね。モダンな言語だとインターフェースの実装はあってもクラス継承はなくなってきています。
27. 自分自身のクラスを示すキーワードは何ですか?
this
。super
は親クラスを指します。
加えるとthis
が指すのは自身のインスタンスです。
28. ポリモルフィズムとは何ですか?
ポリモーフィズムって書いてないとゾワゾワします。
ある要素が複数の型に属することを指します。
29. ダックタイピングとポリモルフィズムの違いを教えてください。
あらかじめインターフェースを定義せずに多態性を利用するのがダックタイピングです。動的型付け言語の特徴のひとつですね。
ポリモーフィズムを利用する場合は事前にフィールドやメソッドの定義を行う必要があります。
30. カプセル化のメリットは何ですか?
複数のデータや操作をひと塊として扱えるようになります。
情報の隠匿とかよりこれが重要です。
31. アクセス演算子って何ですか?
アクセス修飾子。
カプセル化を実現するための仕組みのひとつで、要素へのアクセスレベルを制限します。
C#ではデフォルトでinternalです。
Access Modifiers (C# Reference)
32. タプルとはなんですか?
値の組です。C#7からは無名タプルがサポートされました。
無名タプル
使うには.NET Framework 4.7以上が必要です。使えない場合はTuple型を使いましょう。
Tupleクラス
33. クラスを使うメリットは何ですか?
カプセル化ができます。
34. 例外処理はどうやって書きますか?
try
{
hoge.ExceptionMethod();
}
catch(HogeException ex)
{
}
catch(Exception e)
とかcatch{}
とかはやめましょう。あとスタックトレースを消さないように気を付けましょう。
35. バージョン管理システム(SCM)とは何ですか?
Gitのこと。SVN?知らない子ですね。
ファイルの変更履歴を管理できるシステムです。
36. バージョン管理システム(SCM)は何を使ってますか?
GitHubとGitBucketを使っています。
37. スクリプト言語とコンパイル言語の違いは何ですか?
スクリプト言語は簡単に読み書きできる言語の総称で、コンパイル型言語と比較するならインタプリタ型言語でしょう。
あらかじめコンパイラを通して機械語のソースに変換しておくのがコンパイル型言語。
実行時にインタプリタを通して逐次翻訳していくのがインタプリタ型言語。
コンパイル型は動作が高速、インタプリタ型は修正が比較的容易です。
38. データベースって何ですか?
何かの定義に従って整理された情報の集合のことです。
おそらく広くイメージするのはRDBMS。これは複数の属性をセットとして情報を扱う形式のデータベースです。SQL ServerとかMySQLとか。
対してKey-Valueのセットで保存しテーブルを持たないNoSQLというものもあります。ただし全部がKVS方式ではないですが。
39. トランザクション管理って何ですか?
一連の処理をひと塊として扱うことです。処理の単位をトランザクションといいます。
トランザクションの途中で処理に失敗したときに、その一処理だけでなくトランザクションごとロールバックされます。
40. スレッドって何ですか?
まず実行中のプログラムがプロセスです。プロセスは処理を行うために1個以上のスレッドを内部に持っています。このスレッドがCPUコアに対して命令を送って処理を行います。
ということで、スレッドはプロセス内部の命令を実行する部分です。
【図解】CPUのコアとスレッドとプロセスの違い・関係性、同時マルチスレッディング、コンテキストスイッチについて
41. プリミティブ型とオブジェクト型って何ですか?
組み込み型と参照型のこと。言語仕様として実装しているのが組み込み型。
でもStringは組み込み型だけど参照型だって?
値型と組み込み型を混同している説。
値型の変数はスタック領域に確保されます。
参照型の変数はヒープ領域に確保されます。
例えばintは値型の組み込み型で、Stringは参照型の組み込み型です。構造体は値型のユーザ定義型です。
42. 無名関数/匿名関数って何ですか?
関数名を宣言をせずに使える関数です。
(int x) =>
{
hoge.Method();
}
ラムダ式は匿名関数です。
C#開発者が「ラムダ式が最初からあれば、匿名メソッド式の構文はC#には不要だった」といっているので、まあラムダ式が使えればいいんじゃないでしょうか。
43. メタプログラミングって何ですか?
プログラムを扱うプログラムを書くこと。
あるいはコードを生成するコードを書くこと。
DB情報を読み取って対応するDTOを自動生成するのなんかがこれなんでしょうか。
44. Optionalはどのようなケースで使用しますか?(java/Swift)
null安全のお話ですね。
null安全でない言語は、もはやレガシー言語だ
C#8からnull安全が導入されました。機会があったら使ってみたいですね。
45. リフレクションとは何ですか?
クラス名やメソッド名といったメタデータをプログラム実行時に取り出すための機能です。
C#だとAttributeやprivateメソッドのテストなんかで関わってきます。
ちなみに果てしなく遅いです。
46. クラス拡張はできますか?
C#では拡張メソッドがあります。
47. インスタンス変数にメソッドを追加できますか?
C#ではできません。
48. アノテーションはどのように使用しますか?
Javaだと@Override
とか書きますね。
C#だとAttributeです。
Enum型に付けてメソッド拡張とかで使うこともできますが遅いのでやったことないです。
49. DIコンテナとは何ですか?
まずDependency Injectionから。邦訳するとオブジェクトの注入で、要は移譲では?とか考えています。
ある処理をするためのインスタンスをフィールドに持っておき、処理を行うときはそのインスタンスを通じて実行します。
これを実現するためのツール(あるいはフレームワーク)がDIコンテナです。
50. ガベージコレクションとはなんですか?
参照されなくなったメモリ領域を解放するための仕組みです。
C++などはメモリを手動で管理していましたが、C#などではメモリの解放を自動で行います。
C#ではマーク&スイープ方式と3世代の世代別GCを行っています。
51. ガベージコレクションを使うとなんのメリットがありますか?
プログラマがメモリを意識することが減ります。
逆にいえばメモリを意識したチューニングをするときにはGCが邪魔になることがあります。
52. ARCとは何ですか?
Automatic Reference Counting、参照の自動追跡でGCの一種です。
インスタンスへの参照をカウントしておき、0になったらメモリを解放します。
53. Weakキーワードはどのような局面で使用しますか?
ARCでカウントする参照は強参照と呼ばれています。これに対してARCでカウントされない参照を弱参照と呼び、Weak
を使って変数宣言して使います。
強参照同士でインスタンスを結びつけるとメモリが解放されなくなるため、弱参照を使ってGCを行います。
54. スタック領域とヒープ領域の違いは何ですか?
スタック領域はOSやコンパイラが割り当てと解放を行い、サイズはコンパイル時に定まります。
ヒープ領域はアプリケーションが割り当てと解放を行い、サイズは動的に指定します。
55. 横断的処理の記述方法を教えてください。
おそらくアスペクト指向プログラミングのことでしょう。
オブジェクトとして分離できないLoggerなどをアスペクトとして扱い、アスペクト記述言語を使って分離することで柔軟なプログラムにすることです。
AOP(Aspect Oriented Programming) の解説
56. クロージャって何ですか?
JavaScriptで出てくるやつ。C#でも使えます。
Func<int, Func<int>> method = x =>
{
return () => ++x;
};
var increment = method(100);
Console.WriteLine(increment()); // => 101
Console.WriteLine(increment()); // => 102
methodがクロージャです。このときのint型変数xをレキシカル変数と呼びます。これはスコープの限定された静的な変数です。
incrementに代入した時点でmethodの変数xに100がバインドされ、その後incrementを呼び出すときはバインドされた変数を参照します。
関数型の考え方に踏み込んでいくので、なかなか理解が難しい部分かもしれません。
57. 高階関数って何ですか?
関数を引数や戻り値とする関数のことです。
C#ではデリゲート型オブジェクトにメソッドを格納することができ、デリゲート型を引数や戻り値とすることで高階関数を実現しています。
LINQも高階関数を使っています。
58. ブロック構文って何ですか?
Rubyのdo-end
構文のことらしいです。
hoges.each do |hoge|
hoge.method()
end
こんな感じで使いますね。具体的に何をやってるかはイマイチ分かりませんでした。
Rubyをやっていてブロック処理(do 〜 end)がちゃんとわかってない人は、怒らないから見ていきなさい
59. 変数に関数を設定してください。
デリゲート型を使ってください。
Func<>
が戻り値があるデリゲート型、Action<>
が戻り値のないデリゲート型です。
60. 部分適用とカリー化の違いは何ですか?
どちらもラムダ式の引数を減らすものです。
クロージャに対して仮引数を定めているものが部分適用、減らした後の引数が1個だけのものに対して行うのがカリー化です。つまりカリー化は部分適用の一種です。
クロージャの項も参考にしてください。
61. モナドって何ですか?
モナドは単なる自己関手の圏におけるモノイド対象です。何も問題ないですね。