struct - Go

最終更新日: 2026-07-25

TOP(About this memo)) > 一覧(Go) > struct

宣言

empty struct

ポインター

type A struct {
	A string
	B int
}
func main() {
	a := A{"aaa", 3}
	fmt.Printf("%v %v %v", &a, &a.A, &a.B)// &{aaa 3} 0xc000010018 0xc000010028
}

ネスト

リテラルのショートハンド

  s := []struct {
      i int
      b bool
    }{
      {2, true},
      {3, false},
      {5, true},
      {7, true},
      {11, false},
      {13, true},
    }
  /* 以下のショートハンド(構造体を宣言して、その構造体のsliceを作成)
  type XXXX struct {
    i int
    b bool
  }
  s := []XXXX {
      {2, true},
      {3, false},
      {5, true},
      {7, true},
      {11, false},
      {13, true},
    }
  */
pendingMemberIdAndUserId := util.Map(pendingMembers, func(p repository.PendingMember) struct {
			pendingMemberId string
			userId          string
		} {
			return struct {
				pendingMemberId string
				userId          string
			}{
				p.ID, p.UserId,
			}
		})
...
pendingMemberIdAndUserId = append(pendingMemberIdAndUserId, struct {
				pendingMemberId string
				userId          string
			}{
				existPendingMember.ID, existPendingMember.UserId,
			})

シャローコピー、ディープコピー

t := &T{1, "aaa"}
	a := *t
	a.A = 2
	fmt.Printf("%v\n%v", *t, a) // {1 aaa} {2 aaa}
package main
import "fmt"
type a struct {
  a string
	b string
}
type b struct {
	c string
	d a
}
func main() {
	aa := &b{}
	fmt.Println(aa)//&{ { }}
	bb := &b{}
	*bb = *aa 
	bb.c = "test"
	bb.d.a = "test2"
	fmt.Println(bb)//&{test {test2 }}
	fmt.Println(aa)//&{ { }}
}

複雑な構造体のディープコピー

レスポンスで、構造体 -> 他の構造体へコピーしたい箇所をどうするか?

embbed

package main

import "fmt"

func main() {
	fmt.Println(S2{}.M1())
	fmt.Println(S2{}.M2())
	fmt.Printf("%+v", S2{})

	//var a S1 = S2{} // 埋め込みをしてサブタイプになるわけではない。

	/*

	m1
	m2 overrided
	{S1:{} int:0 Mt:}% // 埋め込みをすると埋込したフィールドが追加される

	*/
}

type S1 struct {
}

func (s S1) M1() string {
	return "m1"
}

func (s S1) M2() string {
	return "m2"
}

type S2 struct {
	S1
	int
	Mt
}

type Mt string

func (s S2) M2() string {
	return "m2 overrided" //オーバーライド可能
}
package main

import (
	"fmt"
)

type i1 interface {
	fu() string
}

type s1 struct {
	f1 string
}

func (s s1) fu() string {
	return s.f1
}

type s2 struct {
	f1 string
}

func (s s2) fu() string {
	return s.f1
}

func f1(a1 i1) {
}

type s3 struct {
	s1
	s2
	i1
	f1 string
}

func main() {
	v := s3{f1: "3", s1: s1{f1: "1"}, s2: s2{f1: "2"}}
	fmt.Printf("%#v \n", v)       // main.s3{s1:main.s1{f1:"1"}, s2:main.s2{f1:"2"}, i1:main.i1(nil), f1:"3"} 
	fmt.Printf("%#v \n", v.s1.f1) // 1
	fmt.Printf("%#v \n", v.s2.f1) // 2
	fmt.Printf("%#v \n", v.f1)    // 3
	fmt.Printf("%#v \n", v.s1.fu())// 1
	fmt.Printf("%#v \n", v.s2.fu())// 2
	//fmt.Printf("%#v \n", v.fu()) // ambiguous selector v.fu
    // f1(v): cannot use v (variable of type s3) as i1 value in argument to f1: s3 does not implement i1 (ambiguous selector s3.fu)
}
type i1 interface {
	fu() string
}
type s1 struct {
	f1 string
}
func f1(a1 i1) {}
type s3 struct {
	s1
	f1 string
}
func main() {
	v := s3{}
	fmt.Printf("%#v \n", v) 
	f1(v)// embbedすることでinterfaceを実装したことになる。
}
package main

import "fmt"

type Test interface {
	A(a string)
}

type S struct {
	Test //s.Test.A("")でもアクセスできるし、s.A("")もアクセスできる。
}

func (s *S) A(a string) {
	fmt.Println("s:" + a)
}

type T struct {
}

func (t *T) A(a string) {
	fmt.Println("t:" + a)
}

func main() {
	s := &S{}
	s.A("test")
	// s.Test.A("test") //panic

	s.Test = &T{}
	s.A("test")
	s.Test.A("test")
}

interface へ 埋め込み??

type i interface {
	int
}

func f(a i) {// error: cannot use type i outside a type constraint: interface contains type constraints

}

埋め込んだ構造体が同じ同名フィールドを保つ場合

(参考)エラーの実装

type processError string
func (e processError) Error() string {
	return string(e)
}

type ErrUnexpectedProcess struct{
	processError
}

func newErrUnexpectedProcess(message string) ErrUnexpectedProcess {
	return ErrUnexpectedProcess{
		processError(message),
	}
}

type ErrExpectedProcess struct{
	processError
}

func newErrExpectedProcess(message string) ErrExpectedProcess {
	return ErrExpectedProcess{
		processError(message),
	}
}

サンプルコード

package main

import (
	"encoding/json"
	"fmt"
)

type ErrorData struct {
	Message string `json:"message"`
}

type response[T any] struct {
	Result string    `json:"result"`
	Error  ErrorData `json:"error"`
	Data   []T       `json:"data"`
}

func (r *response[T]) Set(result string, err string, data []T) {
	r.Result = result
	r.Error = ErrorData{
		Message: err,
	}
	r.Data = data
}

type MyResponse struct {
	response[any]
}

type MyResponse2 struct {
	response[string]
}

type MyResponse3 struct {
	response[int]
}

// メソッドのオーバーライド(のようなこと)も可能
func (r *MyResponse3) Set(result string, err string, data []int) {
	r.Result = result
	r.Error = ErrorData{
		Message: err,
	}
	r.Data = []int{500}
}

func main() {
	// 埋め込んだresponseがinterfaceのResponseIFを満たしているため、responseを埋め込んだ複数の型を利用できる。
	setHttpResponse(&MyResponse{}, []any{struct{ ID string }{ID: "my id"}})
	setHttpResponse(&MyResponse2{}, []string{"aaa", "bbb", "ccc"})
	setHttpResponse(&MyResponse3{}, []int{})

	// 埋め込みはサブタイプ化ではないため、response型として使うことはできない。
	// setHttpResponse2[string](MyResponse2{}, []string{"aaa", "bbb", "ccc"})
}

type ResponseIF[U any] interface {
	Set(result string, errMessage string, data []U)
}

func setHttpResponse[DATA any, RES ResponseIF[DATA]](res RES, data []DATA) {
	res.Set("success", "", data)
	j, _ := json.Marshal(res)
	fmt.Println(string(j))
}

func setHttpResponse2[DATA any](res response[DATA], data []DATA) {
	res.Set("success", "", data)
	j, _ := json.Marshal(res)
	fmt.Println(string(j))
}