- 型( Types )
-
型 というのは 値 の データ形式 を 分類・定義 です。
詳細で厳格な分類は必ずしも必要ではありませんが、型 の 整合性 を厳格に検証することで 記述ミス や 設計ミス を コンパイラ で 発見しやすくなり、より 信頼性 の高いプログラムを組むための助けにもなります。
- 基本データ型( Basic Data Types )
-
言語で定義された 型 で、全て 予約語
で、その名の通り 基本要素 の データ形式 で、その他の型の 基 になります。
また、C言語 などとよく似た分類ですが、詳細は異なります。
- 整数型
-
桁数と符号の有無で分類・定義されています。
符号付き 符号なし サイズ ※ byteubyte8bit shortushort16bit intuint32bit longulong64bit centucent128bit 将来のため予約 整数値 を扱うほとんどのケースで
32bitのintまたはuintが適切な選択で、明確 な必要性があるとき以外に他の選択をする意味もほとんどありません。 - 浮動小数点数型
-
浮動小数点数 サイズ 虚数型 複素数 float32bit ifloatcfloatdouble64bit idoublecdoublereal最大桁数 irealcreal浮動小数点数 は CPU の扱いも別物で、整数型 に比べ、値の保持や計算に 余計なコスト がかかりますから、必要な時以外はintなどの 整数型 を使います。整数型 の計算では 小数点が切り捨てられますから、
import std.stdio; void main(){ // 整数値の計算 int i = 19; float f = 19; writeln( i / 4 ); writeln( i % 4 ); // 余り // 浮動小数点の計算 writeln( f / 4 ); writeln( f % 4 ); }
D:\Pen-Jr\My Programs\types>test 4 3 4.75 3
小数点を扱うには 浮動小数点数型 の明示が必要です。
小数点数 は一般的ですが、浮動小数点数型 を必要とする 処理 は、数学的な処理 を除くとほとんどなく、また、数学的な処理 を必要とすることも限られますから、浮動小数点型 が必要になるケースも限られます。 - 文字型
-
文字コード
(符号なしの整数値)を持つ 型 です。
文字コード char8bit UTF-8 wchar16bit UTF-16 dchar32bit UTF-32 文字コードも整数値ですが、
import std.stdio; void main(){ /* ^ 整数値 33 から 64 までを ^ 文字型で出力する ^ ^ 0 付近は制御コードだから避けた ^ (33 から 64 にしたのは適当) */ foreach( char c; 33 .. 65 ){ byte i = c; // 整数型に変換 wchar wc = c; // wchar型に変換 // i、c、w は全部同じ値を出力する write( i, " : ", c, " = ", wc ); // 見た目を整える(1行の出力を4つ) // i が 0 でなく かつ i が 4 で割り切れるか if( i && !( i % 4 ) ){ writeln(); } else{ write( " " ); } } }
※&&D:\Pen-Jr\My Programs\types>test 33 : ! = ! 34 : " = " 35 : # = # 36 : $ = $ 37 : % = % 38 : & = & 39 : ' = ' 40 : ( = ( 41 : ) = ) 42 : * = * 43 : + = + 44 : , = , 45 : - = - 46 : . = . 47 : / = / 48 : 0 = 0 49 : 1 = 1 50 : 2 = 2 51 : 3 = 3 52 : 4 = 4 53 : 5 = 5 54 : 6 = 6 55 : 7 = 7 56 : 8 = 8 57 : 9 = 9 58 : : = : 59 : ; = ; 60 : < = < 61 : = = = 62 : > = > 63 : ? = ? 64 : @ = @
writeはcharやwchar型 の値を受け取ると、その数値(文字コード)ではなく 文字 として出力します。 -
ブール値(
bool) -
trueかfalseのどちらかの値のみ持てる 8bit の 型 です。import std.stdio; void main(){ // bool値宣言 bool b; writeln( // 初期値は false b, '\n', b = true, '\n', // 整数値 0 か 1 でも OK b = 0, '\n', b = 1 ); /+ b = 10; // これはエラー +/ }
D:\Pen-Jr\My Programs\types>test false true false true
- 構造データ型( Derived Data Types )
-
- ポインタ
- 配列( Arrays )
- 連想配列( Associative Arrays )
- デリゲート
- ユーザー定義型( User Defined Types )
-
プロパティ(
Properties) -
型 の プロパティ は言語仕様を正確に知る必要がある時などに便利です。
- 型の共通プロパティ
-
プロパティ ※ .init初期値 .sizeofサイズ(バイト単位) .alignofアライメント .mangleofmangle 表現文字列 .stringof文字列表現 pragma( msg, // 整数型の初期値 "-- Integral Types --\n", bool.init, "\n", byte.init, ", ", ubyte.init, "\n", short.init, ", ", ushort.init, "\n", int.init, ", ", uint.init, "\n", long.init, ", ", ulong.init, "\n" // 浮動小数点型の初期値 "\n-- Floating Point Types --\n", float.init, "\n", double.init, "\n", real.init, "\n" // 文字型の初期値 "\n-- Char Types --\n", char.init, "\n", wchar.init, "\n", dchar.init );
-c指定でコンパイルD:\Pen-Jr\My Programs\types>dmd test -c -- Integral Types -- false cast(byte)0, cast(ubyte)0u cast(short)0, cast(ushort)0u 0, 0u 0L, 0LU -- Floating Point Types -- nan nan nan -- Char Types -- '\xff' '\U0000ffff' '\U0000ffff'
他もいろいろ
pragma( msg, "-- sizeof/alignof/mangleof --\n", // 整数型 "bool = ", bool.sizeof, "/", bool.alignof, "/", bool.mangleof, "\nbyte = ", byte.sizeof, "/", byte.alignof, "/", byte.mangleof, "\nshort = ", short.sizeof, "/", short.alignof, "/", short.mangleof, "\nint = ", int.sizeof, "/", int.alignof, "/", int.mangleof, "\nlong = ", long.sizeof, "/", long.alignof, "/", long.mangleof, // 浮動小数点型 "\n\nfloat = ", float.sizeof, "/", float.alignof, "/", float.mangleof, "\ndouble = ", double.sizeof, "/", double.alignof, "/", double.mangleof, "\nreal = ", real.sizeof, "/", real.alignof, "/", real.mangleof, // 文字型 "\n\nchar = ", char.sizeof, "/", char.alignof, "/", char.mangleof, "\nwchar = ", wchar.sizeof, "/", wchar.alignof, "/", wchar.mangleof, "\ndchar = ", dchar.sizeof, "/", dchar.alignof, "/", dchar.mangleof, );
-c指定でコンパイルD:\Pen-Jr\My Programs\types>dmd test -c -- sizeof/alignof/mangleof -- bool = 1u/1u/b byte = 1u/1u/g short = 2u/2u/s int = 4u/4u/i long = 8u/8u/l float = 4u/4u/f double = 8u/8u/d real = 10u/2u/e char = 1u/1u/a wchar = 2u/2u/u dchar = 4u/4u/w
※realのアライメントは謎?? - 整数型のプロパティ
-
プロパティ ※ .max最大値 .min最小値 符号には 1bit 消費します。
pragma( msg, /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * 最大値の比較 */ int.max, " = ", // 2進数リテラル 0b0111_1111_1111_1111__1111_1111_1111_1111, "\n", uint.max, " = ", 0b1111_1111_1111_1111__1111_1111_1111_1111, "\n\n", /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * 最小値の比較 */ int.min, " = ", 0b1000_0000_0000_0000__0000_0000_0000_0000, "\n", uint.min );
-c指定でコンパイルD:\Pen-Jr\My Programs\types>dmd test -c 2147483647 = 2147483647 -1u = -1u -2147483648 = -2147483648u 0u
- 浮動小数点数型のプロパティ
-
プロパティ ※ .max最大値 .min_normal.infinity無限大 .nanNaN .dig精度の桁数 .epsilon最小増分値 .mant_dig仮数部のビット数 .max_exp指数の最大値 .max_10_exp.min_exp指数の最小値 .min_10_exp.re実部 .im虚部 整数型 とは別物です。
pragma( msg, /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * dig(精度の桁数) */ "-- dig --\n", float.dig, "\n", double.dig, "\n", real.dig, /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * max */ "\n\n-- max --\n", float.max, "\n", double.max, "\n", real.max, /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * min_normal */ "\n\n-- min_normal --\n", float.min_normal, "\n", double.min_normal, "\n", real.min_normal );
D:\Pen-Jr\My Programs\types>dmd test -c -- dig -- 6 15 18 -- max -- 3.40282e+38 1.79769e+308 1.18973e+4932 -- min_normal -- 1.17549e-38 2.22507e-308 3.3621e-4932
浮動小数点数型 は 整数型 とは扱いが違い、コスト も 別物 です。
NaNというのは「数ではない」という 値 で、無限大 というのは「無限大」という 値 ・・・ということだと思います。虚数だとか、複素数だとか、要するにとっても数学的な処理のためにあるのが 浮動小数点型 ということですから 別物 なわけで、一般的な小数点計算に使うことも出来ますが、その必要性は要考慮です。
- リテラルの接尾辞
-
リテラルの 型 を指定するには 接尾辞 を使います。
- 文字列リテラル( String Literals )
-
接尾辞 型 cchar[]wwchar[]ddchar[]pragma( msg, // デフォルト "\"ABC\" : ", typeof( "ABC" ), // 接尾辞 c "\n\"0123\"c : ", typeof( "0123"c ), // 接尾辞 w "\n\"Welcome\"w : ", typeof( "Welcome"w ), // 接尾辞 d "\n\"Beginner\"d : ", typeof( "Beginner"d ) );
D:\Pen-Jr\My Programs\types>dmd test -c "ABC" : string "0123"c : string "Welcome"w : immutable(wchar)[] "Beginner"d : immutable(dchar)[]
- 整数リテラル( Integer Literals )
-
接尾辞 型 LlonguU符号なし uLUL
LuLUulongpragma( msg, // デフォルトは int "0123 : ", typeof( 0123 ), // 接尾辞 u, U "\n0123u : ", typeof( 0123u ), "\n0123U : ", typeof( 0123U ), // 接尾辞 L "\n\n0123L : ", typeof( 0123L ), "\n456uL : ", typeof( 456uL ), "\n789LU : ", typeof( 789LU ) );
D:\Pen-Jr\My Programs\types>dmd test -c 0123 : int 0123u : uint 0123U : uint 0123L : long 456uL : ulong 789LU : ulong
- 浮動小数点数リテラル( Floating Literals )
-
接尾辞 型 fFfloatLreali虚数型 pragma( msg, // デフォルトは double "0.123 : ", typeof( 0.123 ), "\n123f : ", typeof( 123f ), "\n456F : ", typeof( 456F ), "\n789L : ", typeof( 789L ), // これは long "\n0.789L : ", typeof( 0.789L ), // これが real // 虚数型 "\n\n0.123i : ", typeof( 0.123i ), "\n0.123fi : ", typeof( 0.123fi ), "\n0.123Li : ", typeof( 0.123Li ) );
D:\Pen-Jr\My Programs\types>dmd test -c 0.123 : double 123f : float 456F : float 789L : long 0.789L : real 0.123i : idouble 0.123fi : ifloat 0.123Li : ireal
- 変数
-
変数 というのは、値の格納場所 に 名前(識別子
) を付けたもので、その 識別子 を 変数 として使うための 宣言 が必要です。
- 宣言( Declarations )
-
宣言時には 型 と 記憶クラス を明確にする必要があり、曖昧な宣言は叱られます。
- 初期化子( Initializer )
-
初期化子 は任意で、省略された場合はその型の デフォルト初期値
で初期化されます。
import std.stdio; void main(){ // int 型の変数 i を宣言して 0 で初期化 int i = 0; // 同 j を宣言、int.init で初期化 int j; writeln( "i = ", i, ", j = ", j ); }
D:\Pen-Jr\My Programs\types>test i = 0, j = 0
- 宣言の列挙
-
同じ属性と型の場合は
,区切りで並べて宣言でき、それぞれの初期化子は任意です。string s = "ok", str; int i, j = 100, k;
異なる型の
,区切りは、/* ! -c 指定コンパイルだよ */ /+ // これは NG だけど int ia, string sa, double fa; +/ // 型推論なら OK auto i = 0, s = "string", f = 0.5; pragma( msg, q{ auto i = 0, s = "string", f = 0.5; }, "\ti : ", typeof( i ), "\n\ts : ", typeof( s ), "\n\tf : ", typeof( f ) );
D:\Pen-Jr\My Programs\types>dmd test -c auto i = 0, s = "string", f = 0.5; i : int s : string f : double - typeof
-
式の 型 を得ることが出来ます。
typeof( 式 )変数宣言 でも、
// 式の型で宣言 typeof( 10 ) i; // int型宣言 typeof( 0u ) ui; // uint型宣言 typeof( 0L ) l; // long型宣言 pragma( msg, q{ typeof( 10 ) i; typeof( 0u ) ui; typeof( 0L ) l; }, "\ti : ", typeof( i ), "\n\tui : ", typeof( ui ), "\n\tl : ", typeof( l ) );
D:\Pen-Jr\My Programs\types>dmd test -c typeof( 10 ) i; typeof( 0u ) ui; typeof( 0L ) l; i : int ui : uint l : long - 暗黙の型推論( Implicit Type Inference )
-
宣言 に 記憶クラス
と 初期化子 があれば 型 を省略することも出来ます。
リテラル で、
// 初期化子( リテラル )で型推論 const i = 0, ui = 0u, l = 0L; static s = "Str", ws = "Ws"w; pragma( msg, q{ const i = 0, ui = 0u, l = 0L; static s = "Str", ws = "Ws"w; }, "\ti : ", typeof( i ), "\n\tui : ", typeof( ui ), "\n\tl : ", typeof( l ), "\n\ts : ", typeof( s ), "\n\tws : ", typeof( ws ) );
D:\Pen-Jr\My Programs\types>dmd test -c const i = 0, ui = 0u, l = 0L; static s = "Str", ws = "Ws"w; i : const(int) ui : const(uint) l : const(long) s : string ws : immutable(wchar)[]関数の返値で、
// 返値がstring型の関数 string getString(){ return ""; } // 返値がint型の関数 int getInteger(){ return 0; } // 関数の返値で型推論 auto s = getString, i = getInteger; pragma( msg, q{ auto s = getString, i = getInteger; }, "\ts : ", typeof( s ), "\n\ti : ", typeof( i ), );
D:\Pen-Jr\My Programs\types>dmd test -c auto s = getString, i = getInteger; s : string i : inttypeof( 初期化子 )と同等ですから、曖昧な宣言が許されないことには変わりありませんし、アバウトな宣言と言うことにもなりません。型推論 は記述が簡単になるだけでなく、言語やアプリケーションの仕様変更時に対応が簡単になるメリットもありますから、初期化子のある宣言の 型 は省略して良いでしょう。
- 記憶クラス( Storage Class )
-
記憶クラス というのは 変数の宣言 を修飾する 属性 で、値の 記憶方法 を指定します。
-
const( Const Attribute ) -
コンパイル時に評価出来る 定数 指定です。
宣言 に
const指定がある 変数 の書き換えは コンパイルエラー になりますから、初期化子 のない
const宣言は問題ですが、const i = 100; const s = "Const String"; // 定数だから pragma で表示出来る pragma( msg, "const i = ", i, "\nconst s = ", s ); // 宣言は出来る const int ci; const string cs; /+ // 以下書き換えはコンパイルエラー ci = 100; cs = "Const String"; +/
コンパイル(
-c指定 )ではD:\Pen-Jr\My Programs\types>dmd test -c const i = 100 const s = Const String
エラーにはなりません。
また、
const指定された 変数 は、コンパイラ に 定数 扱いされるだけで、ポインタ などの参照を介しての書き換えは許されます。 -
immutable( immutable Attribute ) -
不変 データ 指定。
基本的に
constと同じで、immutable指定されたデータでも、実行時の アクセス保護 は保証されませんから、参照を介しての書き換えも可能ですが、その動作は未定義です。あえて「書き換え不可」にすることの メリット はわかりづらいかも知れませんが、const指定でその 変数 の意味が明示することは重要ですし、constよりもimmutableを指定することで、信頼性向上 だけでなくimmutableデータを最小コストで扱うなどの 最適化 のメリットを期待できます。 -
static( Static Attribute ) -
静的インスタンス 指定。
静的 とは言っても
constなどとは全く違う意味で、static指定 の 変数 は、宣言された インスタンス に依存しません。
import std.stdio; int mi; // void staticTest( in int n ){ int i; // static 宣言 static int si; if( n ){ i = i + n; si = si + n; mi = mi + n; writefln( "i = %d, si = %d, mi = %d", i, si, mi ); } else{ // 初期値表示 writefln( "int i = %d\nstatic int si = %d\nint mi = %d", i, si, mi ); } } /*---------------------------- * */ void main(){ foreach( i; 0 .. 10 ){ staticTest( i ); } }
D:\Pen-Jr\My Programs\types>dmd test D:\Pen-Jr\My Programs\types>test int i = 0 static int si = 0 int mi = 0 i = 1, si = 1, mi = 1 i = 2, si = 3, mi = 3 i = 3, si = 6, mi = 6 i = 4, si = 10, mi = 10 i = 5, si = 15, mi = 15 i = 6, si = 21, mi = 21 i = 7, si = 28, mi = 28 i = 8, si = 36, mi = 36 i = 9, si = 45, mi = 45
関数外で宣言した
miと同じです。関数 などの中で 宣言 された 変数 はその呼び出しの都度 初期化 され、関数 が終了するとその 値 は保持されませんが、static指定 された 変数 は、その インスタンス に依存しませんから、その 値 が保持されます。関数内で 宣言 しなければ済むことですが、他では参照の必要がない 変数 は「他から参照されたくない」とか言うわけで・・・
簡単なプログラムで必要になることはないと思いますから、「ということだけ知っていれば良いでしょう。constやimmutableとは違う」 -
auto( Auto Attribute ) - 指定する 属性 がなく、型推論 で宣言したい時使います。
-
scope( Scope Attribute )
指定がないと 宣言 のある スコープ に依存する 書き換え可能な 変数 になります。
-
- 引数( Function Parameters )
- 関数 の 引数 も 変数 です。
- 型の変換
-
- 暗黙変換
-
別の 型 への代入には 型変換 が必要ですが、暗黙変換 出来る場合があります。
- 整数型の暗黙変換
-
値を保持できる変換は 暗黙 です。
void dummy(){ // ; は行終端で改行も空白も同じ byte b; ubyte ub; short s; ushort us; int i; uint ui; long l; ulong ul; float f; double d; real r; // 値を保持できる変換は基本 OK i = b; i = s; l = i; /+ s = i; // エラー i = l; +/ // 符号のあり <-> なし s = us; us = s; i = ui; ui = i; } pragma( msg, "Implicit Conversions Test OK" );
D:\Pen-Jr\My Programs\types>dmd test -c Implicit Conversions Test OK
- 浮動小数点型の暗黙変換
-
import std.stdio; void main(){ float f; double d; real r; // 浮動小数点型同士は全部 OK d = f; r = d; r = f; f = d; f = r; d = r; uint i; ulong l; /+ // 浮動小数点型から整数型 は NG i = f; l = f; +/ // 整数型から浮動小数点型は OK だけど i = 1234567890; f = i; d = i; r = i; writeln( "i = ", i, "\nf = ", f, ", d = ", d, ", r = ",r, "\nf == i ? ", f == i, "\nd == i ? ", d == i, "\nr == i ? ", r == i, ); l = 0x1234_5678_9ABC_DEF0; f = l; d = l; r = l; writeln( "\nl = ", l, "\nf = ", f, ", d = ", d, ", r = ",r, "\nf == l ? ", f == l, "\nd == l ? ", d == l, "\nr == l ? ", r == l, ); }
D:\Pen-Jr\My Programs\types>test i = 1234567890 f = 1.23457e+09, d = 1.23457e+09, r = 1.23457e+09 f == i ? false d == i ? true r == i ? true l = 1311768467463790320 f = 1.31177e+18, d = 1.31177e+18, r = 1.31177e+18 f == l ? false d == l ? false r == l ? true
やっぱり 別物 です。
精度の違いなどでいろいろありやっかいな感じですが、整数型 とは 別物 だということだけわかっていれば問題ありません。
- 文字型の暗黙変換
-
文字型 の 変換 は それぞれ
ubyte、ushort、ulongと同じです。import std.stdio; void dummy(){ char c; wchar w; dchar d; w = c; d = c; d = w; ubyte b; ushort s; uint i; c = b; w = b; w = s; d = b; d = s; d = i; b = c; s = c; s = w; i = c; i = w; i = d; /+ // 値の保持が出来ない変換は NG c = s; w = i; b = w; s = d; +/ pragma( msg, "Implicit Conversions Test OK" ); }
D:\Pen-Jr\My Programs\types>dmd test -c Implicit Conversions Test OK
文字型 はほぼ 整数型 の 別名 扱いですが、別の 型 です。
- リテラルの暗黙変換
-
リテラルは気にせず使っていても、あまり叱られません。
// 文字列リテラル wstring ws = "Welcome"; dstring ds = "Beginner"; // C言語 の文字列へも immutable( char )* cs = "String"; // const や immutable が暗黙変換で外されることはないぜ! // 整数リテラル byte b = 0x10; ubyte ub = 100; short i = 0x123; ushort ui = 123; /+ // 大きすぎるとちゃんとエラーになるぞ byte b2 = 0x100; short i2 = 0x12300; +/ // これらは OK だけど byte b3 = -1; short i3 = -1; uint ui3 = -1; /+ // こいつらは NG ubyte b4 = -1; ushort i4 = -1; +/ pragma( msg, "Implicit Conversions Test OK" );
D:\Pen-Jr\My Programs\types>dmd test -c Implicit Conversions Test OK
ubyte、ushortに、符号付きリテラルが NG なのはちょっと例外。 - bool
- Cast 式
-
暗黙変換 出来ない 型変換 は
castで明示します。cast( CastParam )式CastParamは 宣言 と同じで 記憶クラス と 型 が使えます。- 基本データ型
-
import std.stdio, std.conv; void main(){ // 整数型のキャスト auto i = 0xFEDC_BA98u; writeln( // 16進数表記がわかりやすい "i = 0x", to!string( i, 16 ), "\ncast( ushort )i = 0x", to!string( cast( ushort )i, 16 ), "\ncast( ubyte )i = 0x", to!string( cast( ubyte )i, 16 ) ); // 浮動小数点数型から整数型 auto f = 456.789F; writeln( "\nf = ", f, "\ncast( int )f = ", cast( int )f ); }
D:\Pen-Jr\My Programs\types>test i = 0xFEDCBA98 cast( ushort )i = 0xBA98 cast( ubyte )i = 0x98 f = 456.789 cast( int )f = 456
※ 整数型は上位が切り捨てられる。 - 配列
castは 構造データ型 や ユーザー定義型 の変換ではより強力で有効ですが、castを使った 型変換 は、いわば「型の違法改造」も可能ですから、意味もわからず乱用するのはやめましょう。
基本的にはcastを使わないで済む方法を模索(castが正解の場合でも )した方が正しいスキルが身につくはずです。 - 算術演算時の変換( Usual Arithmetic Conversions )
-
- 整数の昇格( Integer Promotions )
- スコープ( 宣言の参照 )
-
コンパイル時の 静的スコープ( 宣言の参照 ) と実行時の 動的スコープ( 値(インスタンス)の寿命 ) があり、それぞれ正しく理解する必要があります。
「値(インスタンス)の寿命」などは難しすぎるかも知れませんが、まずは「宣言の参照」を出来る限りよく理解して、より正確なコードを書けるよう 日々進化 することです。
- 宣言の参照
-
- 唯一無二の識別子
-
識別子 を 参照 する場合、その 識別子 が 唯一無二 である必要があります。
仮に、
// 整数 i int i; // 浮動小数点 i float i; // 関数 i string i();
とかいう宣言が可能で、
int n = i; // これは 整数 i float f = i; // これは 浮動小数点 i string str = i(); // これは 関数 i
とかで 唯一無二 だし便利じゃね??
あまり便利とも思えませんが、あくまで 仮定 の話ですから、castするとint n = cast( int )i; // どうなの?
唯一無二 にはなりませんし、
テンプレート関数 だと
writeln( i ); // どの i なの? writeln!( float, int )( i, i ); // とか書かなきゃ
せっかく簡単だったのに台無しです。
曖昧になり・・・ちゅうか、言語仕様の再構築が必要になります。また、もっと単純に 再宣言 を可能にすると前の 宣言 を 参照 する手段がなくなりますから、そのデメリットに見合うほどのメリットはないでしょう。 - 別モジュールの識別子( Import )
-
モジュール を
importすると、その モジュール の パブリック な 宣言 を 参照 できますが、importされた 宣言 は別の 宣言 で隠すことが出来ます。import std.stdio, std.windows.charset, std.conv; /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ stdio の writeln を隠す ^ (オーバーロードじゃないよ) */ void writeln( in string ){ write( // ここで writeln を使うと大変!! to!string( toMBSz( "バカめ\n俺は偽物だぜ!\n" ) ) ); } void main(){ writeln( "Welcome Beginner" ); /+ // これ、エラーになっちゃうよ writeln( 100 ); +/ }
D:\Pen-Jr\My Programs\types>test バカめ 俺は偽物だぜ!
ただし、この場合 モジュール名 を使って隠した 宣言 を 参照 することが出来ます。importした 宣言 は隠されても、import std.stdio, std.windows.charset, std.conv; /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ stdio の writeln を隠す ^ (オーバーロードじゃないよ) */ void writeln( in string ){ write( // ここで writeln を使うと大変!! to!string( toMBSz( "バカめ\n俺は偽物だぜ!\n" ) ) ); } void main(){ writeln( "Welcome Beginner" ); // モジュール名を付けて呼ぶ std.stdio.writeln( to!string( toMBSz("\nざまあみたらし団子!" ) ) ); }
D:\Pen-Jr\My Programs\types>test バカめ 俺は偽物だぜ! ざまあみたらし団子!
参照することが出来ます。
- モジュールスコープ
- スコープ文
-
- If 文( If Statement )
D言語 ではほとんど自由な 宣言 が出来ますが、関数 の 先頭などに 宣言場所 の 制約 がある言語仕様もあります。出来る限り、関数の先頭などでまとめて 宣言 することは良い習慣ですし、宣言 や 参照 のミスは慣れても犯し勝ちですから、命名 の仕方を工夫したり、ソースコードにインデントを付けたりすることにも効果があります。
