VS 15 Preview 4でインストールされるC# 7では、導入予定の新機能の一部が利用できる。詳細な説明は兄弟サイトであるBuild Insiderで連載されている岩永信之氏のコラムを参照してほしい。以下では、パターンマッチ/タプルを紹介しよう。
パターンマッチとは、値が特定の「パターン」に当てはまるかをテストして、そのパターンに該当する場合には、そこから何らかのデータを取り出すことを意味する*1。
*1 MSDNブログの「What’s New in C# 7.0」では「that can test that a value has a certain "shape"」と「形状」(shape)と述べられているが、本稿ではこれを「パターン」と言い換えている。
C# 7では定数パターン/型パターン/varパターンなどのパターンが導入され、それを利用するためにis式とswitchステートメントのcase節の構文が拡張されている(パターンの種類については将来的にはさらに拡張されていく予定になっている)。
ショボいサンプルだが、例を見てみよう。
class Program
{
static void FooFunc(object obj)
{
if (obj is string v) // 型パターン
{
WriteLine($"string: {v}");
}
else if(obj is null) // 定数パターン
{
WriteLine("null");
}
else if(obj is var v) // varパターン
{
WriteLine($"other: {v.ToString()}");
}
}
static void Main(string[] args)
{
FooFunc("hello");
FooFunc(null);
FooFunc(1.1);
ReadLine();
}
}
is式を使用する場合には上のコードに示したように「obj is <パターン>」の形式でパターンマッチを行う(強調表示部分)。この場合のパターンマッチの記述方法を以下にまとめる。
パターンに含まれる変数(この場合は変数v)は「パターン変数」と呼ばれ、マッチした場合には、その変数に元の入力値(この場合は変数objの値)が代入される。パターン変数の有効範囲はis式を含む最も内側のスコープになる予定だが、VS 15 Preview 4ではパターン変数が宣言されているステートメント内でのみ有効となっている(以降のリリースでこの制限は緩くなる予定だ)。
switchステートメントのcase節では定数値だけではなく、パターンマッチを記述できるようになる。つまり、分岐を定数ベースではなく型ベースで行えるようになる。上のifステートメントをswitchステートメントに書き直したものを以下に示す。
switch(obj) {
case string v: // 型パターン
WriteLine($"string: {v}");
break;
case null:
WriteLine("null");
break;
case var v: // varパターン
WriteLine($"other: {v.ToString()}");
break;
default:
WriteLine("default: unreached");
break;
}
従来のswitchステートメントとは異なり、型を基準にして、場合分けができているのが分かる。また、新しいswitchステートメントでは、上から順にcase節が評価され最初にマッチした節のボディーが実行されるので、case節の書き方によっては、意図した動作にならない場合がある。さらに、default節は常に最後に評価される。つまり、上のコードでdefault節よりも下にcase節があった場合でも、それはdefault節よりも先に評価される。case節にはwhenに続けて、さらに条件を付加することも可能だ。
タプルとは、複数のデータをひとまとめにして扱うためのデータ構造だ。C#では.NET FrameworkによりTupleクラス(System名前空間)が提供されてはいるが、C# 7では言語要素としてタプル型が追加され、タプルをより使いやすくなっている。
簡単な例を以下に示す。ありがちなパターンだが、これは2つの変数の値を交換するものだ。
static void Main(string[] args)
{
int x = 10;
int y = 100;
(x, y) = (y, x);
WriteLine($"x: {x}, y: {y}");
ReadLine();
}
このようにまとめて扱いたいものをかっこで囲むだけでタプルとして扱える。
タプルの主な用途としては次の2つが考えられる。
タプルの第一の用途はメソッドが複数の値を返送したいという場合にタプルを使用するというものだ。これまでならout引数を使用する/複数の値をパッケージングする型を作成する/Tupleクラスを使用するなどして複数の値を返していたがC# 7ではタプルを使うことで、より簡便、より簡潔に複数の値を戻せるようになる。以下に例を示す。
static (int, int) Calcurate(int x, int y)
{
return (x + y, x - y);
}
static void Main(string[] args)
{
(var x, var y) = Calcurate(1, 2);
WriteLine($"1+2: {x}, 1-2:{y}");
var result = Calcurate(100, 10);
WriteLine($"100+10: {result.Item1}, 100-10: {result.Item2}");
ReadLine();
}
タプル型を戻すメソッドの戻り値型は上のコード例から分かるように「戻り値型をカンマ区切りで記述したものをかっこで囲む」ことで示す。また、戻り値を受け取る側では、最初のCalcurateメソッド呼び出しで行っているようにタプルの要素を別個の変数に受け取ることもできるし、2つ目のCalcurateメソッド呼び出しで行っているように1つの変数で受け取り、後からその要素に「ItemX」の形でアクセスすることもできる。
タプルの要素に名前を付けることも可能だ。名前を持った要素で構成されるタプルを戻り値とするように上のコードを書き換えたものを以下に示す。
static (int sum, int diff) Calcurate(int x, int y)
{
return (diff: x - y, sum: x + y);
}
static void Main(string[] args)
{
…… 省略 ……
WriteLine($"100+10: {result.sum}, 100-10: {result.diff}");
…… 省略 ……
}
Calcurateメソッドでは、タプルの要素名を指定することで、順不同でそれらを返してもよい(強調表示部分)。受け取る側では、「ItemX」ではなく要素名を使って、それらにアクセス可能だ(同じく強調表示部分)。
タプルのもう1つの用途は、タプルにまとめられたデータを個々の要素にバラして、それらを個別の変数に代入することがある。実際には上のコードで既にこれを使用している。
(var x, var y) = Calcurate(1, 2);
Calcurate(1,2)呼び出しの結果は「(3, -1)」というタプルになる。そして、このタプルの各要素を変数xとyに代入をしている。これがタプルの分解(deconstruct)と呼ばれる操作だ(最初の変数の値を交換する例でもタプルの分解が使われている)。
なお、VS 15 Preview 4ではタプルをそのまま使うことはできない。NuGetからValueTupleパッケージをインストールする必要がある。詳細な手順は「What’s New in C# 7.0」を参照されたい。現状では、まだコード解析がうまくないところがあり、タプルを使っているとVSがフリーズするかもしれないので注意しよう。
本稿では、VS 15 Preview 4のインストーラーとIDEについて簡単に見た後、C# 7で導入予定の新機能を幾つか紹介した。VS 15 Preview 4ではIDE周りで開発者がイライラせずにVSを使えるような機能強化が行われていることに加えて、C# 7でも開発者が気持ちよくコードを記述できるような機能が追加されている。今回はパターンマッチとタプルだけを紹介したが、別途、C# 7の新機能についてはさらに詳しく取り上げることにしたい。
Copyright© Digital Advantage Corp. All Rights Reserved.