LoginSignup
10
5

More than 5 years have passed since last update.

Golangでクラスを分割したら疑問点が出た話

Last updated at Posted at 2018-08-25

前提

目的

  • handler()を別クラスにわけたい。mainがあるクラスに機能が集約するのが生理的に気持ち悪いため。

やったこと

ディレクトリ構成

golang_webapp_sample
└── src
    └── main
        ├── golang_webapp_sample.go
        └── handler
            └── http_handler.go

ソース

とりあえずhandler()を別クラスにする。 
この時Handler()と先頭大文字にすることで外部参照可能なメソッドとなる。

http_handler.go
package handler

import (
    "fmt"
    "net/http"
)

func Handler(writer http.ResponseWriter, request *http.Request){
    fmt.Fprintf(writer, "Hello World!")
}

次にメインクラス。
importは以下のように"golang_webapp_sample/src/main/handler"とすれば別クラスのメソッドが呼べる。

golang_webapp_sample.go
package main

import (
    "golang_webapp_sample/src/main/handler"
    "net/http"
)

func main() {
    http.HandleFunc("/", handler.Handler)
    http.ListenAndServe(":8080", nil)
}

参考:Go言語のpackageの作り方: 長くなったコードを別ファイルに切り出す方法

確認

  1. go run golang_webapp_sample.go で起動
  2. http://localhost:8080/ にアクセス
  3. 画面に Hello, World! と表示されたら勝ち
    screenshot2.png

勝った。

この段階で発生した疑問点

クラス…?

なんとなくファイル名を分けてこそみたが、よくよく考えてみると、ここまでクラス定義なんかしていないことに今更気づく。
参考: golang メソッドについてまとめてみた。

ではクラスの説明〜と言いたいところなんですが、golangにはクラスという概念がありません。ではクラスの説明〜と言いたいところなんですが、golangにはクラスという概念がありません。なので、メソッドは型に対して紐づくものまででそれ以上はありません。

なるほど、Golangにはクラスという概念はない。
メソッドの先頭文字が大文字かどうかで参照可能範囲が決まるだけである。
目的にmainがあるクラスに機能が集約するのが生理的に気持ち悪い。 と記載したが、この発想が前提から間違っていたのだ。
(とはいえ、振る舞いを役割によって分割するのは設計上好ましいことに間違いはないだろう。結合は疎に、凝集度は高く)

メソッドの引数…??(未解決 → 解決)

…?これ何で動いてんの?

golang_webapp_sample.go
〜〜
    http.HandleFunc("/", handler.Handler)
〜〜
http_handler.go
〜〜
func Handler(writer http.ResponseWriter, request *http.Request){
〜〜
  • handler.Handlerがもうわからない。百歩譲ってhandler.Handler()ならわかる。そんなメソッドは定義していないが。
  • 引数いらんの???何で????
  • メソッドと思って書いたHandler()は、メソッドのようでメソッドじゃない、少しメソッドな関数なのではという仮説。ここはGolangワールド、Javaのお作法とは違うのだ。

8/26 追記

@K-juju さんからのコメントにて腹落ち。ありがとうございました!

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

http.HandleFuncの定義は上記になります。
引数を見ていただくとわかると思うのですが、第二引数の型が func(ResponseWriter, *Request) となっています。

今回の場合で考えてみると、
handler.Handler の型は func(ResponseWriter, *Request) です
handler.Handler() は(引数は省略します)そもそも返り値がないので、型とかありません。

おそらく勘違いされている点は、

http.HandleFunc("/", handler.Handler)
の handler.Handler の部分は、関数を引数としているだけで、関数を呼び出しているわけではないです。
したがって引数はいらないということだと思います。

関数を引数としているだけで、関数を呼び出しているわけではない
Java的にメソッドじゃメソッドじゃと思ってたんですが、そもそもこの時点で関数を呼び出してるわけじゃなかった。
ありがとうございます!

次やること

10
5
4

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
10
5