LoginSignup
1
0

More than 3 years have passed since last update.

【Go】型の変換を覗いてみる

Last updated at Posted at 2019-06-12

Go初心者の筆者がGoの型周りでハマったところをピックアップしてまとめました。1

変数の型

Goではvarキーワードを用いて変数に静的な型をつけることができます。

var a int
a = 10      // int型に整数を代入
var x = 11  // 宣言時に代入も可能

interface{}を用いて動的な型を変数につけることもできます。
(ここでは割愛します。)

定数の型

先ほどの例において、10のような定数の型はどう定義されているのでしょうか。
The Go Programming Language Specification」では次のように説明されています。

The default type of an untyped constant is bool, rune, int, float64, complex128 or string respectively, depending on whether it is a boolean, rune, integer, floating-point, complex, or string constant.

ここで、型なし定数(untyped contstant)とは、明示的な型がついていない定数のことです。
定数自体に型はついていないが、変数などに代入される際に変数へ型をつけられるような定数のことです。

型なし定数のデフォルトの型(the default type of untyped constant)についても説明しておきます。
明示的な型のない変数(例えばvar xと宣言した時のx)へ型なし定数を代入する場合に、変数につける型が必要となります。さもなければ、型のない値を持った型のない変数が誕生してしまいます。
そこで、そのような型付きの値が必要とされる場合に型なし定数につける型のことをデフォルトの型(default type)と呼びます。

型なし定数のデフォルトの型の対応は次の通りになります。

ブール値 ルーン 整数 浮動小数 複素数 文字列
bool rune int float64 complex128 string

例えば、10のデフォルトの型はint型です.

変数に定数を代入する

変数を宣言した時の型とは異なるデフォルトの型を持つ定数を代入した時の挙動はどうなるのでしょうか。
以下の例で見てみましょう。

sample.go
package main
import (
  "fmt"
  "reflect"
)

func main() {
  var a float64
  a = 1
  fmt.Println(reflect.TypeOf(a));
}

reflectパッケージを利用することで変数の型をみることができます。
この例では、変数afloat64型として宣言されています。
そこに型なし定数である1を代入しています。

これを実行してみましょう。

$ go run sample.go
float64

定数のデフォルトであるint型ではなく、変数に宣言したfloat64になっています。

型のある変数に型なし定数を代入する場合の動作について次のような説明がありました。

A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a variable declaration or an assignment or as an operand in an expression. It is an error if the constant value cannot be represented as a value of the respective type.

要約すると、

  • 定数の型は、
    • 明示的に型を指定できる
    • 変数宣言や代入、式のオペランドとして暗黙的に指定できる
  • 定数の値ををそれぞれの型の値として表すことができない場合はエラーとなる

ということです。

この場合、変数に明示的な型がついているため、定数1の型は暗黙的にfloat64型と指定されています。
デフォルトの型は必要とされていないので、変数aint型となることはありません。

変数の代入と演算子

変数に変数を代入する場合は型が一致していなければなりません。2

演算子についても、変数の型は一致していなければなりませんが、一方が型を持つ変数で、もう一方が型なしの定数の場合はシフト演算子を除いて暗黙の型変換が発生します。

Except for shift operations, if one operand is an untyped constant and the other operand is not, the constant is implicitly converted to the type of the other operand.

例をみてみましょう。

time.Sleep(50 * time.Millisecond)

演算子*について左側は型なし定数50(int型)、右側は静的な型のついた変数time.Millisecond(time.Duration型)となっています。
したがって、型なし定数50time.Duration型に暗黙的に型変換されます。

さて、次の例を考えてみましょう。

var interval = 50
time.Sleep(interval * time.Millisecond)

結論から言って、このコードはコンパイルできずに、エラーとなります。

順に見ていきましょう。
まず、変数intervalに型なし定数50が代入されます。
この時、変数intervalの型は型なし定数のデフォルトの型ある、intとなります。

次に関数time.Sleepの引数に式interval * time.Millisecondを渡しています。
この引数の式に着目すると、変数intervalの型とtime.Millisecondの型が一致していないため、エラーとなることがわかります。

最後に

この辺りは慣れてくればば、ほとんど意識しなくても問題ないのですが、理解が曖昧だと後々つまづきます。
時間があれば動的な型付け等の利用方法についてまとめてみます。

参考


  1. あくまで、「こんな仕様だったな」ということを思い出す目的で書いているので、ザックリとした説明になっています。 

  2. 名前を持つ型や基礎型についてなど、細かい話があります 

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0