0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【自己学習用】はじめてのGo3

Posted at

type

Goではtypeを用いて既存の型を拡張した独自の型を定義できる。
呼び出す際に,型が適合していないとコンパイルエラー。

type ID int
type Priority int

func ProcessTask(id ID, priority Priority) {
}

var id ID = 3
var priority Priority = 5
ProcessTask(priority, id) // コンパイルエラー

構造体(struct)

GOの構造体はメソッドを持つことができ,RubyやJavaでのクラスに近い。
構造体もtypeを用いて宣言し,構造体名のあとにそのフィールドを記述する。
各フィールドの可視性は名前で決まり,大文字で始まる場合はパブリック,小文字はプライベート。

type Task struct {
    ID int         // public
    Detail string  // public
    done bool      // private
}

func main() {
    var task Task = Task{
        ID: 1,
        Detail: "buy the milk",
        done: true,
    }
    fmt.Println(task.ID) // 1
    fmt.Println(task.Detail) // "buy the milk"
    fmt.Println(task.done) // true

    task := Task{} //構造体の生成時に値を明示的に指定しなかった場合は,ゼロ値で初期化
}

コンストラクタ

Goにはコンストラクタがない。
代わりにNewで始まる関数を定義し,その内部で構造体を生成するのが通例。

func NewTask(id int, detail string) *Task {
    task := &Task{
        ID: id,
        Detail: detail,
        done: false,
    }
    return task
}

func main() {
    task := NewTask(1, "buy the milk")
    // &{ID:1 Detail:buy the milk done:false}
    fmt.Printf("%+v", task)
}

メソッド

型にはメソッドを定義できます。メソッドは,そのメソッドを実行した対象の型をレシーバとして受>け取り,メソッドの内部で使用できます。
つまりいわゆる拡張メソッドのこと。
func (メソッドを定義する型名の変数名, メソッドを定義する型名) メソッド名 戻り値 {
}

package main

import (
	"fmt"
)

type Task struct {
	ID     int
	Detail string
	done   bool
}

func NewTask(id int, detail string) *Task {
	task := &Task{
		ID:     id,
		Detail: detail,
		done:   false,
	}
	return task
}

func (task Task) String() string {
	str := fmt.Sprintf("%d) %s", task.ID, task.Detail)
	return str
}

func main() {
	task := NewTask(1, "buy the milk")
	fmt.Printf("%s", task.String()) // 1) buy the milk
}

インタフェース

インタフェースの名前は,実装すべき関数名が単純な場合は,その関数名にerを加えた名前を付ける慣習がある。
Goは,型がインタフェースに定義されたメソッドを実装していれば,インタフェースを満たしているとみなす。
↑のTaskにはString()メソッドを実装しているため,Stringerを引数に取る次のような関数に渡すことができる。

type Stringer interface {
	String() string
}

~省略~

func main() {
	task := NewTask(1, "buy the milk")
	fmt.Printf("%s", task.String()) // 1) buy the milk

	Print(task) // TaskにはStringメソッドを定義しているためエラーにならない
}

func Print(stringer Stringer) {
	fmt.Println(stringer.String())
}

次のような何も指定していないインタフェースを定義すると、どんな型も受け取ることができる関数を定義できる。
定義しなくてもinterface{}と記述すると同じ意味になる。

func Do(e Any) {
  // do something
}

Do("a") // どのような型も渡すことができる

func Do(e interface{}) {
  // do something
}

Do("a") // どのような型も渡すことができる

型の埋め込み

Goでは,継承はサポートされていない代わりに、ほかの型を「埋め込む」(⁠Embed)という方式で,構造体やインタフェースの振る舞いを拡張できる。

package main

import (
	"fmt"
)

type User struct {
	FirstName string
	LastName  string
}

func (u *User) FullName() string {
	fullname := fmt.Sprintf("%s %s",
		u.FirstName, u.LastName)
	return fullname
}

func NewUser(firstName, lastName string) *User {
	return &User{
		FirstName: firstName,
		LastName:  lastName,
	}
}

type Task struct {
	ID     int
	Detail string
	done   bool
	*User  // Userを埋め込む
}

func NewTask(id int, detail,
	firstName, lastName string) *Task {
	task := &Task{
		ID:     id,
		Detail: detail,
		done:   false,
		User:   NewUser(firstName, lastName),
	}
	return task
}

func main() {
	task := NewTask(1, "buy the milk", "Jxck", "Daniel")
	// TaskにUserのフィールドが埋め込まれている
	fmt.Println(task.FirstName)
	fmt.Println(task.LastName)
	// TaskにUserのメソッドが埋め込まれている
	fmt.Println(task.FullName())
	// Taskから埋め込まれたUser自体にもアクセス可能
	fmt.Println(task.User)
	fmt.Println(task.User.FirstName) //Userからもメンバにアクセス可能
	/*
	type Task struct {
		ID     int
		Detail string
		FirstName string
		done   bool
		*User  // Userを埋め込む
	}
	もしTaskにUser配下のメンバと同名のメンバがいたらどうなるか?
	→エラーとはならず共存する
	fmt.Println(task.FirstName)
	fmt.Println(task.User.FirstName)
	*/
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?