3-5 データ型変換

3-5-1 暗黙的な型変換

VB .NET では、データ型が異なる変数の間で代入がおこなわれたり、本来期待されるデータ型と異なる型が演算に使用されると、自動的にデータの型が変換されます。これを、 「暗黙的な型変換」 といいます。

[例] 暗黙的な変換

                  
1: Dim A As Integer = 2, F As Double
2: F = A        'Integer 型の 2 は、Double 型の 2 に変換される
3: A = A And F  'ビット演算なので F の値は Double 型から Long 型に変換

このような暗黙的な型変換は、すべてが可能であるとは限りません。例えば、String 型の "ABC" を Integer 型の変数 A へ代入しようとしても、変換のしようがないのでコンパイルエラーになります。暗黙的な型変換ができるか否かは、型によっても異なるので、最も妥当な方法は、できるだけデータ型をそろえて、暗黙的な型変換は避けるようにすることです。場合によっては、暗黙的な型変換によって、データの精度が落ちたり、あまり意味のない変換になることもあります。例えば、前記の 3 行目では、変数 F において Double 型の 2 を Long 型の 2 に変換しています。Double 型と Long 型では、同じ数値 2 を表すときのビットの並びが異なるため、Double 型である変数 F の本来のビットの並びについてビット演算をしたことにはなりません。

また、暗黙的な型変換は、Option Strict の設定によっても異なります(Options Strict の設定方法については、3-1-5 「Dim 文によるさまざまな変数の宣言」の 「参考」 欄を参照)。

例えば、Option Strict がオフであると、表現範囲の小さいデータと表現範囲の大きいデータとの間で、双方向で暗黙的な変換を記述することができます。以下の例では、表現範囲の小さい Short 型(2 バイト)と範囲の広い Integer 型(4 バイト)との間での、双方向の暗黙的な変換を表しています。この 2 行目も 3 行目も、コンパイルできます。

[例] Short 型と Integer 型との間での型変換

                  
1: Dim X As Short, Y As Integer = 100
2: X = Y  '小←大
3: Y = X  '大←小

しかし、この例において Option Strict がオンの場合、2 行目の記述はコンパイルエラーになります。Option Strict がオンのときは、桁数が足りなくなるかもしれないであろう大きい範囲のデータから、小さい範囲のデータ型への暗黙的な型変換を記述することはできません。また、Option Strict がオンであると、前述のビット演算(A=A And F)において、変数 F の Double 型から Long 型への暗黙的な型変換も、コンパイルエラーになります。

もちろん、Option Strict がオフの場合でも、2 行目の記述を実行するとき、変数 Y のもつ実際の値が変数 X が扱える範囲に収まらないと、オーバーフローとして実行エラーになります。例えば、Y の値が 1 億だと、X の表せる範囲にないので実行エラーになります。Y の値が 1000 ならば、X でも表せるので実行エラーにはなりません。

暗黙的な型変換を避けるためには、できるだけデータ型をあわせるようにすればよいのですが、場合によってはデータ型を統一できない状況もあるでしょう。異なるデータ型を複数扱い、かつ異なるデータ型間でデータの代入が必要な場合は、明示的な型変換の記述をするのが適当です。

3-5-2 明示的な型変換表記

異なるデータ型の変数の間でデータのやり取りをしなければならないなど、データの型変換が必要なとき、VB .NET では、明示的に型変換をする記述が用意されています。以下のような CInt 関数などを使うことによって、明示的に特定のデータ型に変換することができます(ドキュメントでは、これを 「関数」、または 「キャスト演算子」 とよんでいます)。

[例] Single 型を Integer 型に変換

                  
1: Dim A As Integer, F As Single = 3.0F
2: A = CInt(F)  '変数 F を Integer 型に変換

これらの型変換をおこなう演算子には、以下のものがあります(表 3-5)。

型変換の関数 変換後の型
CByte Byte
CShort Short
CInt Integer
CLng Long
CSng Single
CDbl Double
CDec Decimal
CChar Char
CStr String
CBool Boolean
CDate CDate
CObject Object

表3-5 VB .NET の型変換関数

これらの明示的な型変換を利用する場合、Option Strict をオンにしても、型変換に関するコンパイルエラーにはなりません。前記の例の 2 行目は、「A=F」 のように暗黙的な型変換を使うと、Option Strict がオンの場合、コンパイルエラーになります。しかし、明示的に CInt 関数で型変換をすれば、Option Strict がオンであっても、コンパイルエラーにはなりません。

なお、型変換には前記のような VB .NET 固有の表記以外に、.NET Framework クラスライブラリにも型変換用のライブラリがあります。ライブラリの Convert クラスには、Convert.ToDecimal メソッドなど、型変換をおこなうさまざまなメソッドが用意されています(この表記方法を正しく理解するには、第 5 章 「クラスの定義と実装」 のクラスの知識が必要です。とりあえず、Convert クラスというものがあり、Convert.ToDecimal や Convert.ToChar という表記ができると考えておけばよいでしょう)。以下の例は、VB .NET 固有の関数を使った変換と、.NET Framework クラスライブラリの型変換を利用した例です。

[例] String 型を Decimal 型に変換

                  
1:   Dim D1 As Decimal, D2 As Decimal, S As String = "102.25"
2:   D1 = CDec(S)  'String 型 S のデータを Decimal 型に変換
3:   D2 = Convert.ToDecimal(S) 'String 型 S のデータを Decimal 型に変換

3-5-3 文字列への変換

ここでは、文字列の変換について補足します。

あるデータ型を文字列に変換する場合、前項のとおり、CStr 関数を使うか、または Convert.ToString メソッドを使うことができます。

[例] Integer 型データを String 型に変換

                  
1: Dim A As Integer = 100
2: Dim S As String
3: S = CStr(A)
4: S = Convert.ToString(A)

また、文字列操作で注意する点として、以下のような 「+」 演算子を使った文字列演算では、暗黙的な文字列への変換は起こらないので注意が必要です。この例では、"ABC" と変数 X の文字列連結のようにみえますが、文字列連結は起こりません。Integer 型の変数 X は、String 型への暗黙的な変換はされません。

[例] 暗黙的な文字列変換はおきない

                  
1: Dim X As Integer = 100, S As String
2: S = "ABC" + X  '文字列連結できない

「+」 演算子が文字列連結に使えるのは、前後の演算項目が String 型のときだけです。VB .NET では前後の一方が数値だと加算処理として機能するので、逆に "ABC" を数値に変換しようとします。もちろん、数値に変換できません。この 2 行目は、Option Strict がオフなら実行エラーに、オンならコンパイルエラーになります(Options Strict については、3-1-5 「Dim 文によるさまざまな変数の宣言」の 「参考」 欄を参照)。

前述の 2 行目で正しく文字列連結をするには、明示的な文字列への型変換が必要です。

[例] 明示的な文字列への変換

                  
1: Dim X As Integer = 100, S As String
2: S = "ABC" + CStr(X)  '文字列 "ABC100" になる

なお、数値を文字列に変換するとき、カンマで 3 桁区切りに表示するなど、書式付きの整形が必要な場合もあります。書式付きの変換には、VB .NET で提供される Format 関数や、.NET Framework クラスライブラリにある String クラスの Format メソッドを利用することができます(String.Formatという記述の正確な意味を理解するには、第 5 章 「クラスの定義と実装」 のクラスの知識が必要です。とりあえず、こう書くと覚えておけばよいでしょう)。詳しい書式指定については、関連ドキュメントを参照してください。以下にいくつかの例をあげておきます(WinApp2 プロジェクトの Form1.vb がもつ、Button1_Click イベントハンドラ内に記述することを想定しています)。

[例] 書式付き文字列変換

                  
 1: Private Sub Button3_Click(ByVal sender As System.Object, ...
 2:     Dim S As String
 3:     Dim X As Integer = 1250000, Y As Integer = 3500
 4:     Dim A As Short = 2000, B As Short = 2000
 5:
 6:     '変数 X の値を文字列 "1,250,000" に変換
 7:     S = Format(X, "#,##0")
 8:     MsgBox("S = " + S)
 9:
10:     '変数 Y の値を使って、文字列 "S =  3,500" に変換
11:     S = String.Format("S = {0,6:#,##0}", Y)
12:     MsgBox(S)
13:
14:     '変数 A、B の値をそれぞれ 16 進形式、10 進形式で表示
15:     '文字列 "07d0 2000"
16:     S = String.Format("{0:x4} {1}", A, B)
17:     MsgBox(S)
18:
19: End Sub
参考  

● String クラス Format メソッドの書式

Format メソッドは、さまざまな書式で文字列を整形できる便利なクラスです。基本的には、以下の 3 行目のように、括弧 { } を含む文字列を使って整形後の文字列を表します。

[例] Format メソッドで数値を文字列として挿入


                        
1: Dim A As Integer = 1000, B As Integer = 20, C As Integer = 30
2: Dim S As String
3: S = String.Format("Data= {0}, {1}, {2}", A, B, C)

3 行目における変換後の文字列は、"Data = 1000, 20, 30" です。つまり、括弧 {0}、{1}、{2} は、後ろに続く A, B, C の挿入位置を示しています。ゼロの位置には、先頭の A の値が文字列として挿入されます。それに続く、{1} は B を、{2} は C を挿入します。

この {0} という表記は、書式をともなうこともでき、{0:書式} というように記述します。以下は、カンマ区切りの書式にあわせて変換されます。

[例] カンマ区切りの変換


                        
3: S = String.Format("Data = {0:#,##0}, A)  ' "Data = 1,000"

また、挿入位置での桁数も指定できます。例えば、7 桁分のスペースを使いたいのであれば、以下のようになります。

[例] スペース 7 桁分で表示


                        
3: S = String.Format("Data = {0,7:#,##}", A) ' "Data =   1,000"

つまり、括弧 { } を使った記述は以下のような形式になります。

{データの特定,桁数:書式}

また、指定された桁数よりも、挿入すべき文字列が短い場合は、既定では右詰めで表示されます。もし、左詰めにしたいのであれば、桁数の前に 「マイナス」 をつけます。

[例] データ ABC を左詰めで挿入


                        
1: Dim S As String, X As Integer = 1000
2: S = String.Format("Data=[{0,7:#,##0}]", X)   '右詰め
3: S = String.Format("Data=[{0,-7:#,##0}]", X)  '左詰め

この例では、2 行目は右詰めで、"Data=[ 1,000]" となりますが、3 行目の場合は、"Data=[1,000 ]" と左詰めになります。

3-5-4 Boxing

すでに、3-2 「値型と参照型」 でも説明したように、データには値型と参照型があり、参照型とはある実体を参照する型のことで、String 型や Object 型の変数は、参照型の変数として扱われました。

値型変数のデータをこのような参照型の変数へ代入すると、値型のデータそのものが型変換されて、参照型の変数自体に代入される訳ではありません。

VB .NET では(というよりも .NET Framework では)、値型データを参照型変数に代入しようとすると、新たにヒープメモリにデータの実体が確保され、その新しいデータ実体の参照情報が、参照型変数に代入されます。これを 「Boxing」 といいます。

以下の例では、値型である Integer 型のデータが、参照型である Object 型の変数に代入されています(Object 型は、VB .NET における最も基本的な汎用性あるデータ型です。Object 型の詳細は、第 5 章 「クラスの定義と実装」 で改めて扱います)。 以下の Object 型変数 Ob1 は参照型であるので、Integer 型の変数 Va1 の値 「100」 が、そのまま変数 Ob1 に代入される訳ではありません。値 「100」 をもったデータの実体が自動的にメモリに確保され、そのメモリ位置を参照するための位置情報が、変数 Ob1 に代入されます。

[例] Integer 型から Object 型への代入文 boxing

                  
1: Dim Va1 As Integer = 100
2: Dim Ob1 As Object
3: Ob1 = Va1  'Boxing

2 つの変数の関係を図示すると、以下のような関係になります(図 3-16)。

図 3-16 Boxing

図 3-16 Boxing

このしくみは、プログラミングの安全性を高めるためにあります。もし、値がそのまま代入できてしまったらどうなるでしょうか。参照型の変数が 100 という値をもったとしたら(実際にはありえませんが)、メモリ上の 100 番地という特定の領域を参照する意味になるかもしれません。もしそうなれば、参照型変数に自由に数値を代入して、そのプログラムの管理下にない任意のメモリ位置を自由にアクセスできるようになり、それは望ましいことではありません。

.NET Framework では、そのような自由なメモリアクセスができないよう、Boxing によって参照型変数の参照すべき場所は、ヒープメモリ上の管理可能な適切な場所になります(ここでいう管理可能な場所とは、Common Language Runtime によって管理されるメモリ空間のことです)。

3-5-5 Unboxing

Unboxing は、前項の Boxing の反対の機能です。参照型から値型に代入すると、参照型変数が参照していたヒープメモリにあるデータ実体の値が、値型の変数に代入されます。なお、Unboxing をしても、もとのデータ実体が消滅する訳ではありません。参照型で扱うデータの実体は、少なくとも参照型変数が参照しなくなるまで維持されます。最終的には、参照型で扱われるデータの実体は、ガベージコレクタによって解放されます(3-3-3「参照型としての配列変数」 の 「基礎知識 & キーワード」 欄を参照)。

[例] Object 型から Integer 型への代入による Unboxing

                  
1: Dim Va1 As Integer = 100
2: Dim Ob1 As Object
3: Ob1 = Va1  'Boxing
4: Va1 = Ob1  'Unboxing

ただし、前記 4 行目は、Option Strict がオンのとき、コンパイルエラーになります。この変換は、Object 型という汎用データ型から Integer 型という特定のデータ型への変換なので、大きい範囲を扱えるデータから、限られた小さい範囲を扱えるデータ型への変換とみなされます(3-5-1 「暗黙的な型変換」 を参照)。Option Strict をオフにすればコンパイルできますが、もし Ob1 変数が "ABC" という文字列を参照していれば、Integer 型の Va1 には代入できず、実行エラーになります。

Unboxing における 2 つの変数の関係を、以下に示します(図 3-17)。

図 3-17 Unboxing

図 3-17 Unboxing

<< 前のページ  次のページ>>

目次