BETA

初めてのgolangと戸惑いポイント

投稿日:2019-01-01
最終更新:2019-01-01
※この記事は外部サイト(https://qiita.com/developer-kikikaikai/ite...)からのクロス投稿です

はじめに

2019年、明けましておめでとうございます。転記記事です。

新しい言語に触る時は、慣れてしまえばなんてことはないけど、最初は詰まるポイントってある気がするので、初学者目線での覚書を残しておきます。
まだ使いだしたばかりですが、感覚としては、python, rubyの使い勝手がいいところを取り入れたコンパイル言語と捉えるとなんとなくしっくり来る気がしました。
言語仕様の独特だな~と思う部分は、きっと作った方の好みなんだろうな。

動作環境: Ubuntu 18.04
言語version: go version go1.10.4 linux/amd64

環境構築

まずは言語自体をインストールします。

sudo apt install golang

その後、必要なpackageをインストールしていきます。
この辺りの使い勝手はrubyのgemsやpythonのpipと似た感じなので、これらをやられてた方ならあまり違和感ないか…

戸惑いポイント: packageインストール方法が複数ある

…と思いきや、packageのインストール方法が複数存在。最初??ってなりました。
インストール方法としては、以下があります。

#go install : golang標準でサポートしているpackageをインストールする(だと思う)  
$ go install crypto  
#go get : 外部公開されたpackageをインストールする。ソースコードをgit cloneしてインストールしている模様。  
$ go get  github.com/labstack/echo/  
#-u付きだとローカル環境のパッケージをupdateします。詳細はmanページで  
$ go get -u github.com/labstack/echo/

使い方

基本packageという単位でソースコードを管理し、他のpackageはimportに記載することで取り込むことが出来ます。
同一フォルダにあるコードは常に同一パッケージにする必要がある模様。

package main  

import (  
    "./controller"  
    "io"  
    "github.com/labstack/echo"  
    "github.com/labstack/echo/middleware"  
)

例えば上の例のcontrollerは自作のpackageです。他のファイルで定義した関数等を使う場合は、packageを指定し、フォルダ内で実際の関数を定義してあげる形となります。
main処理はfunc main()で記載。

func main() {  
    //main処理  
}

型の定義は基本変数の後ろに記載する感じ。

type Account struct {  
    Username string  
    Passphrase string  
}

関数の戻り値も同じく後ろに記載します。return値を複数かけるのは便利だと思います。
エラーコードなんかもそうですし、「戻り値がこの時だけ関連データをまとめて渡したいんだよな~」みたいなケースって、実際コード書いてるとちょこちょこ出くわす気がします。

//普通の定義  
func SetAccount(info Account) bool {  
    //設定処理  
    return true  
}  

//return値複数の場合  
func GetAccount(username string) (Account, error) {  
    //取得処理  
    return account, true  
}  

//使う時はこんな感じで片方のreturn値を無視してもOK  
_, err = GetAccount(info.Username)

戸惑いポイント: 変数定義の仕方が複数ある

go言語の変数定義方法は複数あります。

  1. 宣言して定義
  2. 別変数を代入することで定義

1, 2はそれぞれこんな感じ。

package main  

func main() {  
    //素の型定義はvarで記述  
    var case1_data string  
    case1_data = "test"  

    //型定義 + 代入の場合は:=で記述  
    case2_data:= case1_data   
    print(case1_data , "\n")  
    print(case2_data, "\n")  
}

前者は型定義している感があるのですが、後者はそれが無く。
最初に参考にしたサンプルが:=を多用していたのもあり、「なんか型に対して厳しいけど、どこで定義されてるんだこれ?」って混乱したりしました。
(ちゃんと本買って学べば、この辺でつまづくことはないかもしれないですが…)

とにかく、変数定義はvar or :=です。

戸惑いポイント: 使用していないpackageや変数があると、容赦なくエラーとなる。

例えば実際コードを書いてて、動きが見たくてデバッグを入れるために便利なfmt.Printfをちょっと使う。%vでいい感じに構造体丸っと表示してたり色々捗ります。

import (  
    "fmt"  
)  

func xxx {  
    ....  
    fmt.Printf("%v\n", struct_data)  
}

使う時はimportいるね、って思うんですが、デバッグいらなくなって消す時にimportの”fmt”も消さないと怒られます。
お作法的には正しいだろうからまあいいかって感じですが、ちょっとしたイライラポイントだなと思いました。

戸惑いポイント: publicなデータかどうかは名前の付け方(最初に大文字)で決まる

ここが私的に一番直感的でなかったところです。どこにもpublic/privateの為に記述する単語が無いし、かといって外部からの参照は出来ないし…
と混乱しながら調べると、外部参照が出来るデータは、頭が大文字でないといけないとのこと。マジすか
これは変数、構造体、関数全てに共通するルールになってます。

例えばこんな感じでpackageを定義して、

package sample  

//外部参照出来ない  
var privateData= "local"  
//外部参照出来る  
var PublicData = "public"  

//外部参照出来る  
type PublicStruct struct {  
    //外部参照出来る  
    PublicMember string  
    //外部参照出来ない  
    privateMember string  
}  

//外部参照出来ない  
func privateFunc() {  
    print("privateFunc\n")  
}  

//外部参照出来る  
func Publicfunc() {  
    print("Publicfunc\n")  
}

こんな感じで参照しようとすると、

package main  
import (  
    "./sample"  
)  

func main() {  
    print(sample.privateData, "\n")  
    print(sample.PublicData, "\n")  
    var data sample.PublicStruct=sample.PublicStruct{"test", "test"}  
    print(data.PublicMember)  
    print(data.privateMember)  
    privateFunc()  
    sample.Publicfunc()  
}

小文字で定義したものに関わる部分がエラーになります。

$ go run main.go  
# command-line-arguments  
./main.go:7:8: cannot refer to unexported name sample.privateData  
./main.go:7:8: undefined: sample.privateData  
./main.go:9:59: implicit assignment of unexported field 'privateMember' in sample.PublicStruct literal  
./main.go:11:12: data.privateMember undefined (cannot refer to unexported field or method privateMember)  
./main.go:12:2: undefined: privateFunc

ルールがはっきりしているので、馴染めば書きやすい(と思う)要素ですが、いわゆる初見殺しな感は否めなかったです。

最後に

特徴的だけど面白い言語だな~と思いつつ、今まで触ったことのある言語の中で一番初見殺し感が強かったので記事化しました。
それぞれ戸惑いましたが、packageインストールはgithubのリポジトリをそのまま取り込めるという使い勝手の良さだったり、型定義もわざわざ型の名前を書かなくていい方法が用意されているのは嬉しかったり、メリットのある仕様だと思います。
後はpackageのソースコードが手元に残るのも、package内のデバッグが出来て使いやすいですね。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@dOpIa1PQNPi5jLrnの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!