宣言
Declaration:
AliasDeclaration
AliasThisDeclaration
Decl
AliasDeclaration:
alias BasicType Declarator
AliasThisDeclaration:
alias Identifier this
Decl:
StorageClasses Decl
BasicType Declarators ;
BasicType Declarator FunctionBody
AutoDeclaration
Declarators:
DeclaratorInitializer
DeclaratorInitializer , DeclaratorIdentifierList
DeclaratorInitializer:
Declarator
Declarator = Initializer
DeclaratorIdentifierList:
DeclaratorIdentifier
DeclaratorIdentifier , DeclaratorIdentifierList
DeclaratorIdentifier:
Identifier
Identifier = Initializer
BasicType:
BasicTypeX
.IdentifierList
IdentifierList
Typeof
Typeof . IdentifierList
const( Type )
immutable( Type )
shared( Type )
inout( Type )
BasicTypeX:
bool
byte
ubyte
short
ushort
int
uint
long
ulong
char
wchar
dchar
float
double
real
ifloat
idouble
ireal
cfloat
cdouble
creal
void
BasicType2:
*
[ ]
[ AssignExpression ]
[ AssignExpression .. AssignExpression ]
[ Type ]
delegate Parameters FunctionAttributesopt
function Parameters FunctionAttributesopt
Declarator:
BasicType2opt ( Declarator ) DeclaratorSuffixesopt
BasicType2opt Identifier DeclaratorSuffixesopt
DeclaratorSuffixes:
DeclaratorSuffix
DeclaratorSuffix DeclaratorSuffixes
DeclaratorSuffix:
[ ]
[ AssignExpression ]
[ Type ]
TemplateParameterListopt Parameters MemberFunctionAttributesopt Constraintopt
IdentifierList:
Identifier
Identifier . IdentifierList
TemplateInstance
TemplateInstance . IdentifierList
StorageClasses:
StorageClass
StorageClass StorageClasses
StorageClass:
abstract
auto
const
deprecated
enum
extern
final
immutable
inout
shared
nothrow
override
pure
__gshared
Property
scope
static
synchronized
Property:
@ PropertyIdentifier
PropertyIdentifier:
property
safe
trusted
system
disable
Type:
BasicType
BasicType Declarator2
Declarator2:
BasicType2opt DeclaratorSuffixesopt
BasicType2opt ( Declarator2 ) DeclaratorSuffixesopt
Parameters:
( ParameterList )
( )
ParameterList:
Parameter
Parameter , ParameterList
...
Parameter:
InOutopt BasicType Declarator
InOutopt BasicType Declarator ...
InOutopt BasicType Declarator = DefaultInitializerExpression
InOutopt Type
InOutopt Type ...
InOut:
InOutX
InOut InOutX
InOutX:
auto
const
final
immutable
in
inout
lazy
out
ref
scope
shared
FunctionAttributes:
FunctionAttribute
FunctionAttribute FunctionAttributes
FunctionAttribute:
nothrow
pure
Property
MemberFunctionAttributes:
MemberFunctionAttribute
MemberFunctionAttribute MemberFunctionAttributes
MemberFunctionAttribute:
const
immutable
inout
shared
FunctionAttribute
DefaultInitializerExpression:
AssignExpression
__FILE__
__LINE__
Initializer:
VoidInitializer
NonVoidInitializer
NonVoidInitializer:
AssignExpression
ArrayInitializer
StructInitializer
ArrayInitializer:
[ ]
[ ArrayMemberInitializations ]
ArrayMemberInitializations:
ArrayMemberInitialization
ArrayMemberInitialization ,
ArrayMemberInitialization , ArrayMemberInitializations
ArrayMemberInitialization:
NonVoidInitializer
AssignExpression : NonVoidInitializer
StructInitializer:
{ }
{ StructMemberInitializers }
StructMemberInitializers:
StructMemberInitializer
StructMemberInitializer ,
StructMemberInitializer , StructMemberInitializers
StructMemberInitializer:
NonVoidInitializer
Identifier : NonVoidInitializer
宣言の構文
宣言の構文は、基本的に左から右へと読むことができます:
int x; // x は int
int* x; // x は int へのポインタ
int** x; // x は int へのポインタ へのポインタ
int[] x; // x は int の配列
int*[] x; // x は int へのポインタ の配列
int[]* x; // x は int の配列 へのポインタ
配列も、左から右へ読みます:
int[3] x; // xは int の3要素配列
int[3][5] x; // xは int の3要素配列 の5要素配列
int[3]*[5] x; // xは int の3要素配列 へのポインタ の5要素配列
関数へのポインタは function キーワードを使って宣言します:
int function(char) x; // x はcharを引数としてintを返す関数
// へのポインタ
int function(char)[] x; // x はcharを引数としてintを返す関数
// へのポインタ の配列
C風の宣言構文は非推奨となっています:
int x[3]; // x は int の3要素配列
int x[3][5]; // x は int の5要素配列 の3要素配列
int (*x[5])[3]; // x は int の3要素配列 へのポインタ の5要素配列
int (*x)(char); // x はcharを引数としてintを返す関数
// へのポインタ
int (*[] x)(char); // x はcharを引数としてintを返す関数
// へのポインタ の配列
一行で複数のシンボルを宣言をする時は、 全ての変数が同じ型でなくてはなりません:
int x,y; // x と y は int
int* x,y; // x と y は intへのポインタ
int x,*y; // エラー, 2種類の型
int[] x,y; // x と y は intの配列
int x[],y; // エラー, 2種類の型
暗黙の型推論
AutoDeclaration:
StorageClasses AutoDeclarationX ;
AutoDeclarationX:
Identifier = Initializer
AutoDeclarationX , Identifier = Initializer
宣言が StorageClass で始まって、 型のわかる NonVoidInitializer が指定されているとき、 宣言の型は省略することが可能です。
static x = 3; // x はint型
auto y = 4u; // y はuint型
auto s = "string"; // s はimmutable(char)[]型
class C { ... }
auto c = new C(); // c はクラスCのインスタンスへのハンドル
NonVoidInitializer に前方参照を含むことはできません (この制限は将来的に取り除かれる予定です)。 暗黙に推論される型は、 実行時ではなくコンパイル時に静的に決まります。
ArrayLiteral の型は、 静的配列ではなく動的配列と推論されます:
auto v = ["hello", "world"]; // 型は string[]。 string[2] ではない
型の別名
AliasDeclaration は他の型の別名となるシンボルを作り、 その型の代わりとしてどんな場所でも使えるようにします。
alias abc.Foo.bar myint;
別名となっている型は、意味論的には元の型と全く同一に扱われます。 デバッガは二つの型を区別しませんし、関数オーバーロードの際も、 違いは生じません。例として:
alias int myint;
void foo(int x) { . }
void foo(myint m) { . } // ラー。同じ関数fooが二回以上定義されている
別名宣言
型だけでなく、任意のシンボルに対する alias を宣言できます。 例:
import string;
alias string.strlen mylen;
...
int len = mylen("hello"); // 実際には string.strlen() が呼ばれる
次のような別名宣言が全て有効です:
template Foo2(T) { alias T t; }
alias Foo2!(int) t1;
alias Foo2!(int).t t2;
alias t1.t t3;
alias t2 t4;
t1.t v1; // v1 はint型
t2 v2; // v2 はint型
t3 v3; // v3 はint型
t4 v4; // v4 はint型
シンボルの別名は、 長く修飾された名前を省略したり、 シンボルから別のシンボルへ転送する方法として役に立ちます:
version (Win32)
{
alias win32.foo myfoo;
}
version (linux)
{
alias linux.bar myfoo;
}
シンボルを現在のスコープへ ‘import’ するのに alias を利用できます:
alias string.strlen strlen;
alias によってオーバーロードされた関数達をまとめて ‘import’ することも可能で、 その際には、新しく導入される関数は、現在のスコープに存在した関数とさらにオーバーロードされます:
class A {
int foo(int a) { return 1; }
}
class B : A {
int foo( int a, uint b ) { return 2; }
}
class C : B {
int foo( int a ) { return 3; }
alias B.foo foo;
}
class D : C {
}
void test()
{
D b = new D();
int i;
i = b.foo(1, 2u); // B.foo が呼ばれる
i = b.foo(1); // C.foo が呼ばれる
}
注: 型のaliasは、見かけだけではシンボルの alias 宣言と区別できないことがあります:
alias foo.bar abc; // 型? シンボル?
この区別は意味解析のフェーズで行われます。
aliasを式に対して使うことはできません:
struct S { static int i; }
S s;
alias s.i a; // 不正。s.i は式
alias S.i b; // ok
b = 4; // S.i を 4 にする
extern 宣言
記憶域クラス extern つきで宣言された変数の領域は、 モジュール内には確保されません。 同じ名前で変数を定義した別のオブジェクトファイルを リンクする必要があります。 この機能の使いどころは、 C言語のグローバル変数宣言の利用です。typeof
Typeof:
typeof ( Expression )
typeof ( return )
Typeof は、式の型に基づいて型を指定する方法です。 例えば:
void func(int i) {
typeof(i) j; // j の型はint
typeof(3 + 6.0) x; // x の型はdouble
typeof(1)* p; // p の型はintへのポインタ
int[typeof(p)] a; // a の型はint[int*]
writefln("%d", typeof('c').sizeof); // 1を表示
double c = cast(typeof(1.0))j; // jをdoubleへキャスト
}
Expression は評価されず、 その型情報のみが生成されます:
void func() {
int i = 1;
typeof(++i) j; // j はintと宣言される。iは増加しない。
writefln("%d", i); // 1と表示
}
三つほど、特別な場合があります:
- typeof(this) は、例えメンバ関数の外であっても、 非静的メンバ関数の中で this が指すはずの型になることがあります。
- 同様に、typeof(super) は非静的メンバ関数の中で super が指すであろう型になることがあります。
- typeof(return) は、関数の中では、 その関数の返値の型になります。
class A { }
class B : A {
typeof(this) x; // x は B と宣言される
typeof(super) y; // y は A と宣言される
}
struct C {
typeof(this) z; // z は C* と宣言される
typeof(super) q; // エラー。構造体 C には super がない
}
typeof(this) r; // エラー。構造体やクラス宣言の内部でない
Typeof がもっとも有効なのは、 templateを使ったジェネリックなコードを書く時です。
void 初期化子
VoidInitializer:
void
通常、変数は明示的な Initializer で初期化されるか、 その型のデフォルトの値がセットされます。しかし Initializer が void であった場合に限り、 変数は初期化されません。そのような変数が 値をセットされる前に使用されると、未定義動作を引き起こすことがあります。
void foo() {
int x = void;
writefln(x); // 意味のない値を表示
}
ですから、void 初期化子は速度が最優先のコードを最適化する最後の手段としておくべきです。
グローバル初期化子と静的初期化子
グローバル変数と静的変数の Initializer は、 コンパイル時評価が可能でなければなりません。 ポインタが他の関数やデータのアドレスで初期化できるかどうかは、 実装定義です。 実行時初期化は静的コンストラクタを使って行ってください。