goでは、特定の型を元にして、新たに別の型を定義することができます。
例えば、int型を元に「新たに別の型」を定義すると、「新たな型」で独自のメソッドを追加することができます。
(ただのint型が、独自の処理をもった新たな型になります。)
目次
type宣言で新しい型を定義
例として、「Original型
」 と 「Original型
をもとにした Custom型
」 を定義します。
Custom型を別途定義することで、以下のようなことができます。
- 同名メソッドの処理を変更したい
- 独自の新しい処理を追加したい
package main
import "fmt"
type Original struct {
X string
Y string
}
func NewOriginal(x, y string) Original {
return Original{X: x, Y: y}
}
// Func1 .
func (o *Original) Func1() {
fmt.Printf("Original Func1\n")
}
// Func2 .
func (o *Original) Func2() {
fmt.Printf("Original Func2\n")
}
type Custom Original
func NewCustom(x, y string) Custom {
return Custom{X: x, Y: y}
}
// Func1 同名メソッドを定義することでオーバーライド
func (c *Custom) Func1() {
fmt.Printf("Custom Func1\n")
}
// Func3 新しいメソッドを追加
func (c *Custom) Func3() {
fmt.Printf("Custom Func3\n")
}
func main() {
fmt.Println("Original ----------------")
o1 := NewOriginal("hello", "world")
o1.Func1()
o1.Func2()
fmt.Println("Custom ----------------")
c1 := NewCustom("hello", "world")
c1.Func1() // オーバーライドしたメソッドを実行
// Func2はCustom型で定義してないため実行できません。
c1.Func3() // 追加したメソッドを実行
// キャスト
fmt.Println("Cast ----------------")
o2 := Original(c1)
o2.Func1() // Originalのメソッドが実行される
}
Original ----------------
Original Func1
Original Func2
Custom ----------------
Custom Func1
Custom Func3
Cast ----------------
Original Func1
Custom型
のインスタンスは Custom型
で定義したメソッドのみしか実行できません。
キャストで Original型
に変換すると、Original型
で定義したメソッドのみ利用できます。
埋込みフィールドを活用して新しい型を定義
前述の例では、Custom型
のインスタンスは Custom型
で定義したメソッドしか利用できません。
埋込みフィールドを活用すると、Original型
で定義したメソッドも利用できつつ、特定のメソッドだけオーバーライドできます。
Custom型
の定義の違いに注目してください。
package main
import "fmt"
type Original struct {
X string
Y string
}
func NewOriginal(x, y string) Original {
return Original{X: x, Y: y}
}
// Func1 .
func (o *Original) Func1() {
fmt.Printf("Original Func1\n")
}
// Func2 .
func (o *Original) Func2() {
fmt.Printf("Original Func2\n")
}
type Custom struct {
Original
}
func NewCustom(x, y string) Custom {
return Custom{Original{X: x, Y: y}}
}
// Func1 同名メソッドを定義することでオーバーライド
func (c *Custom) Func1() {
fmt.Printf("Custom Func1\n")
}
func main() {
fmt.Println("Original ----------------")
o1 := NewOriginal("hello", "world")
o1.Func1()
o1.Func2()
fmt.Println("Custom ----------------")
c1 := NewCustom("hello", "world")
c1.Func1() // オーバーライドしたメソッドを実行
c1.Func2()
}
Original ----------------
Original Func1
Original Func2
Custom ----------------
Custom Func1
Original Func2
代入時のCastの必要有無
タイプ定義によって作られた新しい型は、キャストが必要なものと不要なものが存在します。
タイプ定義の元となる型の種類によってキャストの必要有無が変わります。
タイプ定義の元となる型 | 例 | キャスト必要有無 |
---|---|---|
predeclared ( Goで事前定義された型 ) | int, string, bool, float64… | 必要 |
type literal | ArrayType StructType PointerType FunctionType InterfaceType SliceType MapType ChannelType | 不要 |
エイリアス宣言という宣言も存在します。合わせて動作確認します。
エイリアス宣言は、リファクタ用途に利用されるものです。名前が違うだけで、同じ型(よって、新しいメソッドを追加できない)なので、当然キャストは不要です。
package main
import "fmt"
type MyInt1 int // Type definitions(タイプ定義)
type MyInt2 []int // Type definitions(タイプ定義)
type MyInt3 = int // Alias declarations(エイリアス宣言)
func main() {
mi1 := MyInt1(100)
mi2 := MyInt2([]int{100, 200})
mi3 := MyInt3(100)
var i1 int
var i2 []int
var i3 int
// Cast必要
i1 = int(mi1)
// Cast不要
i2 = mi2
// Cast不要
i3 = mi3
fmt.Printf("mi1 %v %T\n", mi1, mi1)
fmt.Printf("mi2 %v %T\n", mi2, mi2)
fmt.Printf("mi3 %v %T\n", mi3, mi3)
fmt.Printf("i1 %v %T\n", i1, i1)
fmt.Printf("i2 %v %T\n", i2, i2)
fmt.Printf("i3 %v %T\n", i3, i3)
}
mi1 100 main.MyInt1
mi2 [100 200] main.MyInt2
mi3 100 int
i1 100 int
i2 [100 200] []int
i3 100 int