LoginSignup
0
0

More than 5 years have passed since last update.

goの継承の仕組みを試してみて

Last updated at Posted at 2018-11-20

ちょっとgoはモックが一筋縄では以下なさそう(特に既存のパッケージをモックしたい場合)なので、その解決策をひねり出すべく、一旦継承の仕組みについて調べてみたのでまとめ。
やっぱり自分が覚えるのは書くのが一番なので。。。

main.go

package main

import (
    "fmt"
    "time"
)

/*
User という構造体を定義する。
これがオブジェクトの基本になるイメージ。
*/
type User struct {
    Name string
}

/*
funcで始まるが、これはメソッドであり関数とは違うもの。
宣言のイメージ的に、第一引数のUserに対して、Nowというメソッドを
使えるようにしてあげますよ・・・という感じになる。
*/
func (u User) Now() time.Time {
    fmt.Println("User::Now() has called")
    return time.Now()
}

/*
ChikokuUser (遅刻ユーザー) という構造体を定義する。
これは継承先のオブジェクトの基本になるイメージ。
一応 ExtParam というものを追加で持っている。
*/
type ChikokuUser struct {
    User
    ExtParam string
}

/*
ChikokuUser の Now をオーバーライドする。
同じように ChikokuUser 構造体に対して同名のメソッドを追加し、
事実上のオーバーライドをしている。
*/
func (cu ChikokuUser) Now() time.Time {
    fmt.Println("ChikokuUser::Now() has called")
    n := time.Now()
    // 俺的にはまだ5時間余裕がある。なので遅刻する。
    n = n.Add(-5 * time.Hour)
    return n
}

func main() {
    // 遅刻ユーザーを宣言する。第一引数はUser構造体で、第二引数が文字列(->ExtParamになる)
    cu := ChikokuUser{User{"keiichi"}, "this is ext param"}
    fmt.Println(cu.ExtParam) // --> ExtParamである "this is ext param" が表示される

    oretekiNow := cu.Now() // --> 俺的Nowは5時間前。overrideされた ChikokuUser::Now() が呼ばれる
    layout := "2006-01-02 15:04:05 MST"
    fmt.Println(oretekiNow.Format(layout)) // --> 整形して表示
}

実際に実行するとこうなる。

% date ; go run main.go
Tue Nov 20 16:14:31 JST 2018
this is ext param
ChikokuUser::Now() has called
2018-11-20 11:14:31 JST <-- 5時間前の時刻になっている

もし、この状態で、 func (cu ChikokuUser) Now() time.Time のブロックだけをコメントアウトした上(オーバーライド解除)で実行するとこうなる。

% date ; go run main.go
Tue Nov 20 16:14:11 JST 2018
this is ext param
User::Now() has called
2018-11-20 16:14:12 JST <-- ちゃんと今の時刻

とりあえずオーバーライドは成功していたということになるのではないかと。

まずgoを覚えていて最初に理解が出来てなかったのは、 関数メソッド が違うものであるということ。
オブジェクト指向ではないため、構造体にメソッドを埋め込む様なイメージで宣言する感じ。
イメージ的にPerlのblessに近い感じがした。

大筋はコード中のコメント参照。具体的には継承先のstruct側で同名メソッドを定義することで事実上オーバーライドをしている。

pythonでいうsuperとかしたい場合はどうするといいのかな・・・とは思っているが今は触れないでおく。

これで、既存のパッケージを使いつつ、引数をうまいことinterface化できればいけるのではないか・・・頭では考えているが、そう上手くいくかどうかは次回また考える。

追記

oretekiNow := cu.User.Now()

のようにすると、Python でいう super.Now() 的に呼び出すことが出来るそうです。

※ zetamatta さんありがとうございます。

0
0
2

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