🍒

[Go] 言語仕様書に出てくる型関連の用語まとめ

2021/12/07に公開

Golangの言語仕様書に登場する型関連の単語の関係について整理し、微妙な違いをわかりやすくするのがこの記事の目的です。

PredeclaredとComposite Type

Goの型は主に二つに類別できます[1]

複合型は型リテラル(Type literal)struct{...}interface{...}chan int等)によって構成されます

// Predeclared type
int
bool
string
float32

// Composite type
struct{a, b int}
interface {}
chan int
[]string
[5]string
[int]string

Defined type

Goには型に新しい名前を付ける構文が二つあります。

type A string  // type definition
type B = string // alias declaration

各構文によって作られた新しい型は次のようになります。

  • type definitionによって作られた新しい型Adefined typeと言います。
  • alias declarationによって作られた新しい型Bstringaliasと言います。

事前宣言された型もここtype definitionされているのでdefined type です[2] 。今後、type A stringstringにあたる型を参照した型と呼ぶことにします。

Defined typeでない型

Defined typeでない型は複合型です。a~eはDefined typeではありません[3]

// 全てdefined type
var a strunct{a, b int}
var b interface{}
var c chan int
var d []string
var e [5]string

ここまでのDefined typeをまとめると次のようになります。

type A int       // Aはdefined type、intはdefined type
type B []string  // Bはdefined type、[]stringはdefined typeではない
type C = int     // Cはdefined typeではない、intはdefined type

Underlying type

Underlying typeは型Tの基礎となる型のことで、演算や代入をした時の挙動に関わります。各型の挙動を表にまとめました。

Underlying type
事前宣言された型 T T 自身
型リテラルで構築される型 T T 自身
alias T 参照した型と同じ
defined type T 参照した型と同じ

型に新しい名前を付けるための構文は2種類ありましたが、どちらもUnderlying typeを引き継ぎます。例えば、次のようになります。

int              // intのunderlying typeはint
[]string         // []stringのunderlying typeは[]string
type A int       // Aのunderlying typeはint
type B []string  // Bのunderlying typeは[]string
type C = int     // Cのunderlying typeはint

Underlying typeに関しては、言語仕様書の次のリンク先の部分に詳しく書いてあります。
https://go.dev/ref/spec#Types

method set

method setとは

  • インターフェース型Tのメソッドセットはそのインターフェース
  • それ以外の場合、型Tに対して実装されたメソッドの集合

インターフェースを比較する時、method setは重要な概念になります。method setの例を次に挙げます。

package main

import (
	"fmt"
)

type A interface {
	foo()
	bar()
}

type B interface {
	hoge()
}

type MyInt int

func (i *MyInt) foo() {
	fmt.Println("foo")
}

func (i *MyInt) bar() {
	fmt.Println("bar")
}

func (i MyInt) hoge() {
	fmt.Println("hoge")
}

/*
	foo
	bar
	hoge
*/

func main() {
	var x MyInt
	x = 10
	x.foo()
	x.bar()
	x.hoge()
}
  • Aのmethod setfoobar
  • Bのmethod sethoge
  • MyIntのmethod setfoobarhoge

Untyped constant

Goの定数には型を明示するtyped constantと、型を明示しないuntyped constantがあります。

const a int = 10  // typed constant
const b = int(10) // typed constant
const a = 1000000 // untyped constant

untyped constant の利点は、整数定数や実数定数で本来は変数で表現できない値でも定数にできることです。また、nilのようにあらゆる複合型として扱うことも可能です。ただし、変数に代入できなかったり、精度が落ちたりする場合があります。

package main

import "fmt"

func main() {
	const a = 120
	const a = 99999999999999999999999999999999
	const b = 12e+1000000
	const c = 3.14159265359
	_ = int64(a)   // NG
	_ = float32(b) // NG
	d := float32(c)
	fmt.Println(d) // 3.1415927
}

untyped constantと言っても、完全に型がないわけではなく

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 numeric constant,untyped boolean constantなど)が存在しています。定数に関しては、言語仕様書の次のリンク先の部分に詳しく書いてあります。
https://go.dev/ref/spec#Constants

加えた方が良い内容や記事内容に誤りあった場合、コメントで教えていただけると嬉しいです。

参考にさせていただいたサイト

https://go.dev/ref/spec

https://zenn.dev/nobishii/articles/defined_types

https://qiita.com/zr_tex8r/items/7fdef1020d294000f490

https://speakerdeck.com/dqneo/go-language-underlying-type?slide=32

脚注
  1. 便宜的にpredeclared typeと呼んでいますが、predeclared typeは言語仕様書には登場しない単語です。言語仕様書にはpredeclared boolean, numeric, or string typesと書いてあります。 ↩︎

  2. なぜここのような定義がされているかは https://go.dev/ref/spec#Numeric_types に書いてあります。プラットフォームの差を吸収するためです。 ↩︎

  3. ほとんどの構造体やインターフェースは、type.... で定義されていると思うのでdefined typeです。 ↩︎

Discussion