Go

コンストラクタ パターン
type User struct {
Name string
Age int
}
func New(name string, age int) User {
return User{Name: name, Age: age}
}
func main() {
// New = コンストラクタ , user = インスタンス
user := New("tomoki", 21)
fmt.Println(user)
}

レシーバ
ポインタレシーバ:ポインタとして引数で渡すので、関数内でオブジェクトの値を変更できる
値レシーバ:元の値とは別のコピーした値が関数に渡されるので元の値は変更はできない
- その構造体型のデータの値を変えたい時にポインタレシーバを使う
type Square struct {
width float64
height float64
}
func (s Square) Area() float64 {
return s.width * s.height
}

Interfaceを実装(implements)していないとerrorを出す方法
Uberもやっている手法
type Doer interface {
Do()
// Greet()
}
var _ Doer = Person{} // たったこれだけ!
type Person struct {
Name string
}
func (p Person) Do() {
fmt.Printf("My name is %s. I am Doer!!!!\n", p.Name)
}
func main() {
p := Person{Name: "John"}
p.Do()
}

Gorm
以下2つは同じ実装。複数回クエリが走る
err = tx.Preload(clause.Associations).Find(&influencer).Error
err = tx.Preload("Influencer.ActivityAreas").Preload("Influencer.Genres").Preload("Influencer").Where("uid=?", uid).First(user).Error

これで複数テーブルをjoinして取得できる
* Select("*")とすると予期しないidが返ってきた
type I struct {
Influ
Genre
ActivityArea
}
var influencer *model.I = &model.I{}
err = tx.
Table("influencers AS i").
Select("i.*, aa.id, aa.name, g.id, g.name").
Joins("INNER JOIN activity_area_influencers AS aai ON aai.influencer_id = i.id").
Joins("INNER JOIN activity_areas AS aa ON aa.id = aai.activity_area_id").
Joins("INNER JOIN genre_influencers AS gi ON gi.influencer_id = i.id").
Joins("INNER JOIN genres AS g ON g.id = gi.genre_id").
Where("i.id=?", 1).
Scan(&influencer).
Error

NG 1
influencer.ActivityAreasがinfluencer.Genresに上書きされるという事件
var influencer *model.Influencer = &model.Influencer{}
err = tx.Table("influencers AS i").Select("*").
Joins("INNER JOIN activity_area_influencers AS aai ON aai.influencer_id = i.id").
Joins("INNER JOIN activity_areas AS aa ON aa.id = aai.activity_area_id").
Joins("INNER JOIN genre_influencers AS gi ON gi.influencer_id = i.id").
Joins("INNER JOIN genres AS g ON g.id = gi.genre_id").
Scan(&influencer).
Scan(&influencer.ActivityAreas).
Scan(&influencer.Genres).
Error

defer

排他制御

ループして配列に詰める
list := make([]string, 0, len(f.queue))
for _, key := range f.queue {
list = append(list, key)
}
list := make([]string, 0, len(f.queue))
list = append(list, f.queue...)

関数も引数に
package main
import "fmt"
var c *Config
type Config struct {
Func func() string
}
func main() {
c := &Config{
Func: c.init,
}
method := c.Func
method()
}
func (c *Config) init() string {
fmt.Println("hello")
return "init"
}

三項演算子がないので
maxItems := "1"
if recordSetIdentifier != "" {
maxItems = "100"
}
serviceAccountName := "default"
if k6.Spec.Runner.ServiceAccountName != "" {
serviceAccountName = k6.Spec.Runner.ServiceAccountName
}

// 最後の文字を置換する
func replaceLast(s string, laststring string) string {
slice := strings.Split(s, "")
slice[len(slice)-1] = laststring
return strings.Join(slice, "")
}
// n番目の文字を置換する // nが範囲内かどうか確認する処理を入れる。
func replace(s string, new string, n int) string {
slice := strings.Split(s, "")
slice[n] = new
return strings.Join(slice, "")
}
// n番目の文字を抽出する なんかミスってる
func getRuneAt(s string, i int) rune {
rs := []rune(s)
return rs[i]
}

base64デコードしてからファイルに書き込む
src := "SGVsbG8gV29ybGQ="
dec, err := base64.StdEncoding.DecodeString(src)
if err != nil {
log.Fatal(err)
}
kubeconfig := flag.String("kubeconfig", filepath.Join(HomeDir(), ".kube", "config"), "(optional) absolute path to the kubeconfig file")
fmt.Println(*kubeconfig)
f, err := os.Create(*kubeconfig)
if err != nil {
log.Println(err)
}
f.Write(dec)

木構造になっているStructのタグを全て取得する。
*めっちゃ汚い再帰関数
func main() {
var s Users
fetchTree(&s)
}
type Person struct {
N *int `json:"n"`
}
type User struct {
Person Person `json:"person"`
Name string `json:"name"`
Age int `json:"age"`
}
type Users struct {
User1 *User `json:"user1"`
User2 *User `json:"user2"`
}
func fetchTree(i interface{}) {
typ, ok := i.(reflect.Type)
if !ok {
typ = reflect.TypeOf(i)
}
switch typ.Kind() {
case reflect.Ptr:
get(typ.Elem())
case reflect.Struct:
get(typ)
default:
}
}
func get(typ reflect.Type) {
for i := 0; i < typ.NumField(); i++ {
typ2 := typ.Field(i).Type
fmt.Println(typ.Field(i).Name, typ.Field(i).Type, typ.Field(i).Type.Kind(),"-----", typ.Field(i).Tag.Get("json"))
switch typ2.Kind() {
case reflect.Ptr:
if typ2.Elem().Kind() == reflect.Struct {
get(typ2.Elem())
}
case reflect.Struct:
get(typ2)
default:
}
}
}

イメージしやすいように雑にかけば
func get(i interface{}) {
typ, ok := i.(reflect.Type)
if !ok {
typ = reflect.TypeOf(i)
}
for i := 0; i < typ.NumField(); i++ {
typ2 := typ.Field(i).Type
switch typ2.Kind() {
case reflect.Ptr:
for i := 0; i < typ2.Elem().NumField(); i++ {
typ3 := typ2.Elem().Field(i).Type
switch typ3.Kind() {
case reflect.Ptr:
for i := 0; i < typ3.Elem().NumField(); i++ {
typ4 := typ3.Elem().Field(i).Type
switch typ4.Kind() {
case reflect.Ptr:
case reflect.Struct:
default:
}
}
case reflect.Struct:
// 続きがある。
fmt.Println(typ3)
default:
fmt.Println(typ3)
}
}
case reflect.Struct:
// fmt.Println(typ.Field(i).Type)
default:
// fmt.Println()
}
}
}

iotaを使ってenumっぽいことを
package main
import "fmt"
type CleanupType int
const (
All CleanupType = iota
Succeeded
Failed
)
// enumとして作成したtypeに対してインターフェースを実装(Stringメソッドを用意)
func (c CleanupType) String() string {
return [...]string{"all", "succeeded", "failed"}[c]
}
func main() {
fmt.Println(All.String())
}
文字列ベースで

Goカプセル化
package main
type Human struct {
name string
}
// カプセル化
// メソッド名を大文字からはじめることで、publicなスコープにする。
func (human Human) GetName() string {
return human.name
}
// セッターはレシーバをポインタにしないと値が変更されない
func (human *Human) SetName(name string) {
human.name = name
}

Go Generics

Go言語のコンポジションを利用すると、struct内にinterfaceを埋め込むことで、埋め込まれたインターフェースのメソッドを利用することができます。
type Writer interface {
Write(data []byte) error
}
type Logger struct {
Writer
}
func (l *Logger) Log(message string) error {
// Loggerの処理
data := []byte(message)
return l.Write(data)
}

providerInterfaceは、Endpoint()とVerifier(config *oidc.Config)という2つのメソッドを持つインターフェースです。これらのメソッドはoidc.Providerのメソッドと同様の機能を提供する必要があります。
providerFactoryは、ctxとissuerを引数として受け取り、providerInterfaceとエラーを返す関数の型です。providerFactoryOIDCは、oidc.NewProvider(ctx, issuer)を呼び出してproviderInterfaceを生成する具体的な実装です。
このコードの目的は、oidc.Providerの具体的な実装に依存せずに、ユニットテスト時にスタブを使用できるようにすることです。これにより、テストをより独立して実行し、コードの品質と信頼性を向上させることができます。
argo-workflows
type providerInterface interface {
Endpoint() oauth2.Endpoint
Verifier(config *oidc.Config) *oidc.IDTokenVerifier
}
type providerFactory func(ctx context.Context, issuer string) (providerInterface, error)
func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) {
return oidc.NewProvider(ctx, issuer)
}
func New(c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) {
return newSso(providerFactoryOIDC, c, secretsIf, baseHRef, secure)
}

goroutine と channel