🕌

[Go] 構造体の変換と比較

2022/10/08に公開

Goの構造体間で変換できる条件と比較できる条件について書きます。

構造体の変換について

Goの構造体の変換はフィールドの名・型・順番・数が一致していることが前提で変換することができます。例えば以下の様に, AとBでは構造体間の変換が可能です。

package main

import "fmt"

type A struct {
	aa int
	bb int
}

type B struct {
	aa int
	bb int
}

func main() {
	a := A{
		aa: 1,
		bb: 2,
	}
	var b B
	b = B(a) // 変換可能
	fmt.Println(b) //=> {1 2}
}

逆に以下の様に、フィールド名が異なる・フィールドの型が異なる・フィールドの順番が異なる・フィールドの数が異なる、等の状態だと変換することができないです。

package main

type A struct {
	aa int
	bb int
}

type DifferentFieldName struct {
	aa int
	cc int
}

type DifferentFieldType struct {
	aa uint
	bb int
}

type DifferentFieldOrder struct {
	bb int
	aa int
}

type DifferentFieldNum struct {
	aa int
	bb int
	cc int
}

func main() {
	a := A{
		aa: 1,
		bb: 2,
	}
	var d DifferentFieldName
	d = DifferentFieldName(a) // 変換不可: フィールド名が異なる

	var d2 DifferentFieldType
	d2 = DifferentFieldType(a) // 変換不可: フィールド名の型が異なる

	var d3 DifferentFieldOrder
	d3 = DifferentFieldOrder(a) // 変換不可: フィールドの定義順が異なる

	var d4 DifferentFieldNum
	d4 = DifferentFieldNum(a) // 変換不可: フィールドの数が異なる
}

構造体の比較について

Goの構造体が比較可能である条件は、同じ構造体の型であり、かつ全てのフィールドが比較可能である場合は比較できます。 フィールドが比較可能ということは、フィールドにsliceやmapなどが含まれていた場合は同じ構造体であっても比較することができません。

package main

import "fmt"

type A struct {
	aa int
	bb int
}

type B struct {
	aa int
	bb int
}

type C struct {
	aa int
	bb int
	cc []int
}

func main() {
	a := A{aa: 1, bb: 2}
	a2 := A{aa: 1, bb: 2}
	fmt.Println(a == a2) // => true(比較可能)

	b := B{aa: 1, bb: 2}
	fmt.Println(a == b) // 比較不可: 構造体の型が異なる

	c := C{aa: 1, bb: 2, cc: []int{1, 2}}
	c2 := C{aa: 1, bb: 2, cc: []int{1, 2}}
	fmt.Println(c == c2) // 比較不可: 比較できないフィールドが含まれている
}

しかし、ある構造体と無名構造体の比較に関しては型が異なっていても、フィールドの名前・順番・型が同じであれば比較可能です。

package main

import "fmt"

type A struct {
	aa int
	bb int
}

func main() {
	a := A{aa: 1, bb: 2}

	b := struct {
		aa int
		bb int
	}{
		aa: 1,
		bb: 2,
	}
	fmt.Println(a == b) //=> true

	a2 := A(b) // 型変換も可能
}

Discussion