[VB.NET] Integer * String は何型になる?

VB.NET では遅延バインディングをする時を除き、必ず `Option Strict On` するべきです。そうしないと驚くべきことが起きます。もっと悪いことに、驚くべきことが起きていることに気づかないケースも起きます。

今回はそんな驚くべきことの一例をあげます。

Integer * String の結果はどうなる?

以下のコードは意図的に `Option Strict Off` にしています。

Option Explicit On
Option Strict Off
Option Infer On

Module Program
    Sub Main()
        Dim i As Integer = 1
        Dim s As String = Console.ReadLine()
        Dim answer1 = i * s
        Console.WriteLine(answer1.GetType())
        Dim answer2 = s * i
        Console.WriteLine(answer2.GetType())
    End Sub
End Module

この例では Infer On なので、answer1, answer2 は Object 型ではなく、ちゃんと推論され型付けされます。ここでの問題はそれが何型になるかです。(Infer Off では Object 型になりますが、本当の型は GetType() メソッドの呼び出して表示されるので確認できます。)

Integer 型?String 型?

ChatGPT 4o mini 上で試したところ 4 回も間違え、5回目でようやく正解しました。まあ、ネット上にほぼほぼ無い情報なので ChatGPT は学習できないのでしょう。たぶん。

正解は

Double 型です。予想できましたか?

なぜそうなるのか

まず、String は掛け算をする前に Double に変換されます

次に、基本的な二項演算子は両辺の型をそろえたうえで適用されます。今回の operator * は Double で型が揃えられます。そのため Operator * の呼び出し時に、Integer の方も Double に変換されてしまうことに注意してください。

Class Double
    Shared Operator *(left As Double, right As Double) As Double
        Return left * right
    End Operator
End Class

このようなメソッドを呼ぶイメージで、Operator * の計算結果もまた Double であるということになります。

仮に結果で Integer を期待するならば Double から Integer への縮小変換も必要になります。

        ' 型変換の位置を間違えている
        ' 一見正しく動作するので、おそらく間違いに気づかない
        Dim answer1 = CInt(i * s)
        Dim answer2 As Integer = s * i

読み手に苦痛を与え、動作も無駄が多く遅いコードです。

`Option Strict On` にしよう!

今回の例で `Option Strict On` にしていれば、暗黙の型変換を許可しないのでちゃんとコンパイルエラーになります。そして、「String から Double への変換」をしようとしていると教えてくれます。文字列は Double ではなく、Integer として扱わなければならないと気づくことができ、文字列に対して適切にキャストを書くこともできます。

        Dim i As Integer = 1
        Dim s As String = Console.ReadLine()
        Dim answer1 = i * CInt(s)
        Console.WriteLine(answer1.GetType())
        Dim answer2 = CInt(s) * i
        Console.WriteLine(answer2.GetType())

Integer * Integer が Integer になるという、非常に分かりやすく、動作も早いコードになりました。

コンパイラを味方につけましょう。型を意識しましょう。

この記事が気に入ったらサポートをしてみませんか?