20201128のGoに関する記事は6件です。

AtCoder Regular Contest 109のメモ

前置き

Atcoderをやってみたので、自分用のメモです。
あとから加筆・修正する予定です。

問題

https://atcoder.jp/contests/arc109

A

Q_A.go
package main

import (
    "fmt"
)

func main() {
    var a,b,x,y int
    fmt.Scanf("%d %d %d %d", &a, &b, &x, &y)

    var ans int 
    if a == b {
        ans = x
    } else {
        if a > b{
            ans = (a - (b+1)) * y + x    
            if ans > (2 * (a-b) -1) * x {
                ans = (2 * (a-b) -1) * x
            }    
        } else {
            ans = (b - a) * y + x
            if ans > ((1 + 2 * (b-a)) * x) {
                ans = ((1 + 2 * (b-a)) * x)
            }
        }    
    }

    fmt.Printf("%d\n", ans)
}

B

Q_B.go
package main

import (
  "fmt"
)

func main() {
  var n int64
  fmt.Scanf("%d", &n)

  var X int64 = n+1
  var dis int64 =0
  var i int64
  for i=1; ; i++{
    X = X - i

    if X < 0{
      break
    }else{
      dis +=1
    }
  }

  ans := n + 1 - dis

  fmt.Printf("%d\n", ans)
}


C

Q_C.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    var n, k int64
    fmt.Scanf("%d %d", &n, &k)

    var s string
    fmt.Scanf("%s", &s)

    S := strings.Split(s, "")

    ir := make([][]string, k)
    var i, j int64
    for i=0; i < k; i++ {
        ir[i] = make([]string, n)
    }

    var index int64 = 1
    var right int64
    for j=0; j<n; j++{
        right = (j + index) % n
        ir[0][j] = judge(S[j], S[right])
    }

    for i=1; i<k; i++{
        index = (index + index) % n
        for j=0; j<n; j++{
            right = (j+index)%n
            ir[i][j] = judge(ir[i-1][j], ir[i-1][right])
        }
    }

    fmt.Printf("%s", ir[k-1][0])
}

func judge(left string, right string) string {
    if left == right {
        return left
    } else if (left =="R") && (right == "P") {
        return "P"
    } else if (left =="R") && (right == "S") {
        return "R"
    } else if (left =="S") && (right == "R") {
        return "R"
    } else if (left =="S") && (right == "P") {
        return "S"
    } else if (left =="P") && (right == "R") {
        return "P"
    } else if (left =="P") && (right == "S") {
        return "S"
    }
    return "S"
}

D

覚えてたら後で書きます。

E

覚えてたら後で書きます。

F

覚えてたら後で書きます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

goの超初心者向けのチュートリアル

近々go言語に触れるかもしれないので、無知の状態からやってみたことの備忘録です。

前提

・Mac
・とりあえず手っ取り早く動かせる状態にしたい
・go触ったことない

インストール

公式ページからパッケージをインストールするだけ。
https://golang.org/dl/

Homebrewなどでインストールする方法もあるようですがcliに苦手意識あるので簡単なやり方で。。。

開発ツール

とりあえずVisualStudioCode
(vscode最強だと思ってる)

以下の拡張機能を追加。
・Go(https://marketplace.visualstudio.com/items?itemName=golang.Go)
※Go Nightlyという拡張機能は入れないほうがいい(goのプレビュー版で併用して動かせないため)

とりあえずHelloWorld

公式ページのチュートリアルをやってみる

適当な.goファイルを作って以下の内容を記載

main.go
package main

import "fmt"

func main()  {
    fmt.Println("Hello,World!")
}

ターミナルでファイル実行するとHelloWorld表示される

go run main.go
Hello,World!

パッケージの追加

node.jsでいうnode_module的なもの?

main.go
package main

import "fmt"
import "rsc.io/quote" //追加

func main()  {
    fmt.Println("Hello,World!")
    fmt.Println(quote.Go()) //追加

}

ターミナルで以下のコマンドを実行するとgo.modファイル(パッケージ管理ファイル?)とgo.sumファイル(インストール済みのパッケージを記載?)が作られてquoteパッケージの読み込み設定が記載される
(node.jsでいうpackage.jsonですね)

go mod init main 
go.mod
module main

go 1.15

require rsc.io/quote v1.5.2

再度runコマンドを実行すると追加したquoteがインストールされたっぽい。
npm install を自動で実施してくれた感じですね。

ひとまず初めの一歩を踏み出せるところまでです。
公式チュートリアルはまだ続きがあるので、後日追記する。

その他やりたいこと

・自動ビルド?のパッケージがあるっぽいのでそいつを導入してみる
・web画面表示したい

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初学者向け Windows でGoの環境構築をした話

はじめに

普段は製造業の情報システム部で社内SEとしてシステムの保守運用をしている社会人1年目の新人SEです。
普段はJavaをメインで使っているのですが、モダンな技術を知りたく手始めにGo言語の勉強をしようと思います。
環境構築するついでに、これからGo言語で初めてプログラミング言語に触れる初学者の方の助力になればと思いメモ書きとして残しておきます。

環境変数何それ???ってレベルのガチガチの初学者方向けの記事になってしまいましたが丁寧なのに越したことはないはず。。。
あ、パスとかディレクトリは分かっている設定で書いてますので分からない人はググってね。

Goの環境構築

1.インストーラのダウンロード

下記リンクでダウンロードできます。
https://golang.org/dl/

今回はWindows版をダウンロードします。

download.jpg

ダウンロードができたらインストーラを開いてインストールへ!

2.インストール

基本的に特に何もいじらず指示通りインストールすれば問題ないです。

setup1.jpg

setup2.jpg

インストール先は各人のお好みで。
特にこだわりがなければC:\ or D:\ の直下に配置してあげましょう。

後でこのパス使うので覚えるか控えておくかしてね!
setup3.jpg

"Install"を押下するとインストールが始まります。
setup4.jpg

下の画面がでればインストール成功
setup5.jpg

インストールができたら環境変数の設定へ!

3.環境変数の設定

コントロールパネルを開く
システムとセキュリティ → システム → システムの詳細設定 → 環境変数
ennumver.jpg
ennumver2.jpg
ennumver3.jpg
ennumver4.jpg

システム環境変数(S) にある Path を選択して 編集(I) を押下
ennumver5.jpg

自動で登録されていた場合はそのままOKを押して閉じて大丈夫!
ennumver6.jpg

自動で登録されていなかった場合

1.Goをインストールしたディレクトリに移動する
ennumver7.jpg

2.binのパスをコピーする
ennumver8.jpg

3.新規を押下しペーストして完了!
ennumver9.jpg
ennumver10.jpg

環境変数の設定が終わったら最後の確認作業へ!

4.確認

コマンドプロンプトを開いて

go version

と入力しインストールしたものと同じversionが出力されていれば環境変数の設定はできています。

kakunin2.jpg

ここで失敗する場合、環境変数の設定が間違っている可能性が高いのでもう一度環境変数の設定を見直しましょう!
*インストールの際にパスを任意に設定している場合、binのフォルダまで移動して実行すると成功するかも
下記コマンドでbinのディレクトリに移動できます。
("binがあるディレクトリのパス" に実際のパスを入力してください。)

cd "binがあるディレクトリのパス"

では、試しに動くか確かめてみましょう。

"Hellow Go" でも出力してみましょうか
test.go という名前のファイルを作成して、下記内容を記載

package main

import "fmt"

func main() {
fmt.Printf("Hello Go\n")
}

test.goのあるディレクトリで下記コマンドプロンプトを実行する

go run test.go

test3.jpg

無事 Hellow Go が出力されたらOK!

最後に

ガチガチの初学者向けの記事になってしまいましたが、私がプログラミング始めたばかりのころを思い出しながら書いてみました。
分かりにくかったらすいません!
ではみなさん、素敵なGolang lifeを!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Goで始める分散データ処理。Bigsliceパッケージ入門

はじめに

Go言語で開発された有名な製品はDockerやKubernetesを筆頭に数多く存在します。アプリケーション開発としてもWebAPIのバックエンドやCLIツール開発で利用されることも増えていると感じます。IoTの文脈ではTinyGoなど組み込みプログラム領域でも進化を続けていて、WebAssembly(WASM)向けビルドと相まって今後さらなる拡張に期待を持っている人も多いかと思います。

一方で、大規模(1台のサーバに収まらない)データの分散処理分野では、Apache Spark(もちろんHadoop, YARN, etc.)とそのエコシステムが圧倒的に強いと感じます。AWS上であればSparkのマネージドサービスたるAWS Glueがありますし(EMRもありますが)、GCPだとDataprocでSpark(DataflowをApache Beamで扱うことが多そうですが)が広く使われていると思います。

Apache SparkはGoバインドのSDKはありますがαステータス1、Apache BeamもPySparkのようなGo SDK がありますが、experimental2でプロダクション利用は非推奨とのこと。そのため、Goで大規模データに対する分散処理を含んだアプリケーションのロジックを実装するのは既存のフレームワークでは厳しい状態だたと思います。私自身、少なくても日本でこの領域にGoで処理しているという話は聞いたことがないです3。この領域でのGoの存在感は意外なほど小さいです。

Bigslice

bigslice.png

The Bigslice gopher design was inspired by Renee French.

Bigslice is a system for fast, large-scale, serverless data processing using Go.
(Bigsliceは、Goを利用した高速かつ大規模データ処理のためのサーバーレスな仕組みです。)

■Bigslice(公式)
https://bigslice.io/

そんな分散処理界隈ですが、Bigsliceというデータ処理フレームワークが存在します。サーバレスを謳っています。公式ドキュメントにもApache SparkやFlume Javaとの違いを触れていますが、カテゴリーとしては同様と扱って良いと思います。

Map, Filter, Reduce, Joinなどデータのコレクション操作のようなAPIを提供し、Bigslice側でクラウド上にアドホックなクラスタを作成し、透過的に分散処理を行ってくれるとのことです(スゴイ)。通常のGoパッケージと同じくBigsliceパッケージをimportして既存のGoコードと同じ用にコンパイルができるとのこと。これだけだとその凄さが分かるようであまり分からないので、早速使ってみましょう。

サンプルを実行(ローカル端末で実行)

まずは公式ドキュメントのGetting startedにかかれているサンプルコードです。この界隈だとよくある Word Count です。

wordcount.go
package main

import (
    // 省略
    "github.com/grailbio/bigslice"
    // 省略
)

var wordCount = bigslice.Func(func(url string) bigslice.Slice {
    slice := bigslice.ScanReader(8, func() (io.ReadCloser, error) { // 入力読み込み。8はシャード数(分散数)
        resp, err := http.Get(url)
        if err != nil {
            return nil, err
        }
        if resp.StatusCode != 200 {
            return nil, fmt.Errorf("get %v: %v", url, resp.Status)
        }
        return resp.Body, nil
    })
    slice = bigslice.Flatmap(slice, strings.Fields) // 入れ子をフラットに変換
    slice = bigslice.Map(slice, func(token string) (string, int) { // 1単語ごとに数値1と表現(変換)
        return token, 1
    })
    slice = bigslice.Reduce(slice, func(a, e int) int { // 集計処理
        return a + e
    })
    return slice
})

bigsliceパッケージを利用していることが分かると思いますが、ここに分散コレクション操作を実装していきます。最初の func(url string) bigslice.Slice に渡される 引数urlはmain関数から渡されます。

その内部の実装としては以下のようなイメージです。

  1. bigslice.ScanReaderで入力の読み込み。ここではURLのテキストを読み込み
  2. bigslice.FlatmapでSliceと呼ばれるbigsliceの分散データ表現に変換。ここでは文字列に変換
  3. bigslice.Mapで射影(変換処理)。ここでは入力トークンを、キーと数値1に変換
  4. bigslice.Reduceで集計。先程のトークンが同じ場合にReduceが呼ばれ、個々では単語ごとにカウントを合算

この wordCount をmain関数から呼び出します。シェークスピアのテキストファイル(5.2MBほど)をワードカウントしてみます。

wordcount.go
package main

import (
    // 省略
    "github.com/grailbio/bigslice/sliceconfig"
)

const shakespeare = "https://ocw.mit.edu/ans7870/6/6.006/s08/lecturenotes/files/t8.shakespeare.txt"

type counted struct {
    token string
    count int
}

func main() {
    sess := sliceconfig.Parse()
    defer sess.Shutdown()
    ctx := context.Background()

    // 処理の開始
    tokens, err := sess.Run(ctx, wordCount, shakespeare)
    if err != nil {
        log.Fatal(err)
    }

    // 結果読み込み
    scanner := tokens.Scanner()
    defer scanner.Close()
    var (
        token  string
        count  int
        counts []counted
    )
    for scanner.Scan(ctx, &token, &count) {
        counts = append(counts, counted{token, count})
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    // 出現数で降順ソート
    sort.Slice(counts, func(i, j int) bool {
        return counts[i].count > counts[j].count
    })

    // 上位10件を表示
    for _, count := range counts {
        fmt.Println(count.token, count.count)
    }
}

実行してみます。

実行結果
$ go run main.go
2020/11/28 14:32:34 http: serve :3333
the 23242
I 19540
and 18297
to 15623
of 15544
a 12532
my 10824
in 9576
you 9081
is 7851

無事ワードカウントができたようです。the, I, and, to, ofなどが出現数が多いようですね。

Windows環境だと下記エラーが出てしまい実行できないようなので、試すときはWSLなどで実行してみてください。

Windowsで動かした場合
> go run main.go
# github.com/grailbio/base/status
..\..\..\..\pkg\mod\github.com\grailbio\base@v0.0.9\status\stream.go:112:23: undefined: syscall.SIGWINCH
..\..\..\..\pkg\mod\github.com\grailbio\base@v0.0.9\status\term.go:120:8: undefined: syscall.Termios
..\..\..\..\pkg\mod\github.com\grailbio\base@v0.0.9\status\term.go:121:31: not enough arguments in call to syscall.Syscall6
略

AWS環境で実行

透過的にといういうくらいなので、AWSのスポットインスタンスで上記のワードカウントを動かすことができるようです。なんとなくHadoopのMapReduceを思い出します(YARNコンテナではなく、EC2が起動するのはなかなか強いなと思いますね)

仕組みとしては、grailbio/bigmachineを利用しています。こちでEC2を起動しssh経由でEC2にバイナリを送りつける仕組みなようです。

bigslice.png

こうした背景から、事前に公開鍵で認証済みのAMIを作成したり、ssh(22)やHTTPS(443)のインバウンドを許可したセキュリティグループを作成しておいたり、ローカル端末で動かす場合はEC2インスタンスの起動権限を付与したIAMユーザを払い出す必要があります。

ちなみに、AWS上にSecurityGroup名はデフォルトで bigslice です。諸々準備を終えて以下のコマンドで動くとドキュメントに書いています。別記事でこのあたりの設定方法はまとめていきたいと思います。

ざっくり書くと、

①セキュリティグループ+EC2 AMIを作成(ここが長い)
②コマンドインストール($GOPATH/binをPATHに追加していない場合は忘れないように)

bigsliceコマンドのインストール
GO111MODULE=on go get github.com/grailbio/bigslice/cmd/bigslice@latest

③AWSキーを環境変数に載せる。bigsliceはProfileには非対応なようです

キーは適時読み替えください
$ export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
$ export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
$ export AWS_REGION=ap-northeast-1

④セットアップコマンドを実行します。

$ bigslice setup-ec2
bigslice: found existing bigslice security group sg-0f061b686f38ab36b
bigslice: set up new security group sg-0f061b686f38ab36b
bigslice: wrote configuration to /home/mano/.bigslice/config

~/.bigslice/conifg のAMI-IDを書き換え

$ head /home/mano/.bigslice/config
instance aws aws/env

param aws/env region = "ap-northeast-1" // the default AWS region for the session

param bigmachine/ec2system (
        // 省略
        ami = "ami-0f5253b670d69a556" // ★書き換えます
        // 省略

⑥bigsliceコマンドの実行

GO111MODULE=on bigslice run main.go
2020/11/30 23:10:18 http: serve :3333
2020/11/30 23:10:18 slicemachine: 0 machines (0 procs); 1 machines pending (3 procs)
2020/11/30 23:10:18 slicemachine: 0 machines (0 procs); 2 machines pending (6 procs)
2020/11/30 23:10:18 slicemachine: 0 machines (0 procs); 3 machines pending (9 procs)
...

そうすると、下記のようにEC2がデフォルトで3台起動します。端末のbigsliceを殺すとEC2インスタンスが起動しっぱなしになるためご注意ください。

image.png

内部詳細

少しですが公式ドキュメントに記載がありました。

まとめ

EC2をオンデマンドに起動し、分散処理を行うBigsliceパッケージを紹介しました。

GCP、Azureなどには対応していなかったり、AWSでもEC2のみの対応のようですが非常に心くすぐられるパッケージです。

ドキュメントなどがまだ出揃っておらず、試行錯誤が必要ですが上手くハマれば非常に面白いプロダクトであると思います。

今後大規模データに対する分散処理の領域もGo言語でアプリケーションを書く機会が増えていけば良いなと思います。


  1. 2020/11/28現在、READMEを読む限り「2016-07-27: First very alpha version.」と書かれていたことから判断 

  2. 2020/11/28現在、「The Go SDK is currently experimental, does not yet offer any compatibility guarantees and is not recommended for production usage. It supports most features, but not all.」とドキュメントに記載 

  3. 少なくても日本では?。Apache KafkaやAWS Kinesis DataStream などメッセージングサービスを使った逐次処理で比重が傾いて、そもそもこういった需要が減ったからが理由な気がしないでもないです。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCodeに毎日挑戦してみた 35. Search Insert Position(Python、Go)

はじめに

無料英単語サイトE-tanを運営中の@ishishowです。

プログラマとしての能力を上げるために毎日leetcodeに取り組み、自分なりの解き方を挙げていきたいと思います。

Leetcodeとは

leetcode.com
ソフトウェア開発職のコーディング面接の練習といえばこれらしいです。
合計1500問以上のコーデイング問題が投稿されていて、実際の面接でも同じ問題が出されることは多いらしいとのことです。

golang入門+アルゴリズム脳の強化のためにgoとPythonで解いていこうと思います。(Pythonは弱弱だが経験あり)

10問目(問題35)

35. Search Insert Position

  • 問題内容

Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

(日本語訳)

個別の整数のソートされた配列とターゲット値が与えられた場合、ターゲットが見つかった場合はインデックスを返します。そうでない場合は、順番に挿入された場合のインデックスを返します。

**

Example 1:

  Input: nums = [1,3,5,6], target = 5
  Output: 2

Example 2:

  Input: nums = [1,3,5,6], target = 2
  Output: 1

Example 3:

  Input: nums = [1,3,5,6], target = 7
  Output: 4

Example 4:

  Input: nums = [1,3,5,6], target = 0
  Output: 0

Example 5:

  Input: nums = [1], target = 0
  Output: 0

考え方

  1. バイナリーサーチを使って実装しました

  2. midとターゲットを比較して二分探索していきます

  3. 範囲を絞っていき、見つかったらreturnします

  • 解答コード
def searchInsert(self, nums, target): # works even if there are duplicates. 
    l , r = 0, len(nums)-1
    while l <= r:
        mid=(l+r)/2
        if nums[mid] < target:
            l = mid+1
        else:
            if nums[mid]== target and nums[mid-1]!=target:
                return mid
            else:
                r = mid-1
    return l
  • Goでも書いてみます!
func searchInsert(nums []int, target int) int {
    l := 0
    r := len(nums) - 1
    for (r >= l) {
        mid := l + (r - l) / 2
        if (nums[mid] == target) {
            return mid
        } else if (nums[mid] > target) {
            r = mid - 1;

        } else {
            l = mid + 1;
        }
    }
    return l
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[逐次更新]Goのドキュメントを読んでく

背景

同僚達とGoのドキュメントを読んでこうって取り組みを開始しました。
毎週決められた日時で担当者が発表…とはいえ私の理解・予習・復習の為にも、雑に和約っぽいもの(意訳)と個人の感想を書き連ねていきます。
内容の正しさは保証しないので、誤り見つけましたらご指摘ください。
ちょいちょい更新する予定です。

今回読むもの

https://github.com/golang/go/wiki/CodeReviewComments

本題

【Gofmt】

gofmt をコード上で実行すると、自動的に多くの機械的システムの問題を修正します。
ほとんど全てのGoコードがgofmtを使用しております。
このドキュメントの残りの部分は機械的でないスタイルを対象としおります。
gofmtの上位互換であるgoimportsを代わりに使用することもできます。
goimportsは必要に応じてimport行を追加・削除をすることができます。

つまり

VSCodeなりなんだりのGoをサポートしているエディタでgofmtgoimportsのモジュールを使用すれば、自動で修正・importしてくれるよってお話。便利なので忘れずにやらねば。

【Comment Sentences】

参考)https://golang.org/doc/effective_go.html#commentary.
(関数・定数の)宣言時のコメント文は、多少冗長に感じたとしても、完全な文章でなければいけません。
このアプローチによってgodocドキュメントに展開したときのフォーマットが良くなります。
コメントは宣言されているものの名前で始まり、ピリオドで終わる必要があります。

つまり

宣言に対するコメントは、名称で始めて文章にする。(ピリオドで終わらせる)
godoc -http=:8080 でgodocドキュメントを確認してみるか…

Contexts

context.Context型の値には、APIとプロセスの境界を跨いで、セキュリティ証明書・追跡情報・期限・キャンセルシグナルが含まれております。
Goプログラムは明示的に、RPCやHTTPリクエストからリクエストの発信まで、コールチェイン全体に沿ってContextsを渡します。

Contextを使用するほとんどの関数は、Contextを最初の引数として受け取らなくてはいけません。

リクエスト固有でない関数は、context.Background()を使用することができます。しかし必要ないと思っていても、Contextを渡すようにしましょう。
Contextは渡すのがデフォルトです。
Contextを渡すのが間違いであることが明確な時だけcontext.Background()を使うようにしましょう。

構造体にContextメンバを追加しないでください。
代わりにContextが必要な各メソッドにctxパラメータを追加してください。
署名が標準ライブラリやサードパーティ・ライブラリのインターフェイスに一致しなくてはいけないメソッドは例外です。

カスタムContext型を作成したり、関数シグネチャでContext以外のインターフェイスを使用したりしないでください。

アプリケーションデータを渡したい場合は、パラメータ、レシーバ、グローバル変数に入れてください。
もし実際に存在するならば、Contextの値として持たせてください。

Contextsは不変なので、同じctxを、同じ期限・キャンセルシグナル・資格情報・親トレースを持つ多数のcallに渡すことができます。

つまり

Contextは渡すように。メソッドの引数として渡すように。
渡されるメソッドは、引数の最初がctxになるように設計する。

Copying

予期せぬエイリアスを避ける為に、他のパッケージから構造体をコピーする時は気をつけてください。
例えば、bytes.Bufferの構造体は[]byteを含んでおります。
Bufferをコピーすると、コピーしたスライスは元の配列のエイリアスになってしまい、後続のメソッドで呼び出した際に驚くような結果になるかもしれません。

一般的に、T型のメソッドが*Tのポインタ型に関連づいている場合、値をコピーしてはいけません。

Crypto Rand

鍵を生成する時はmath/randパッケージを使用してはいけません。使い捨ての1回限りであってもです。
seedを持たないジェネレーターは完全に予測可能です。
time.Nanoseconds()のseedを持つものでも、ほんの少し予測ができます。
代わりに、crypto/randのリーダーを用いて、テキストが必要な場合は16進数かbase64を用いましょう。

つまり

鍵生成はcrypto/randを用いる

Declaring Empty Slices

空のスライスを宣言する時はt := []string{}ではなくvar t []stringを使いましょう。

var t []stringではnilのスライス、t := []string{}ではnilではない長さゼロのスライスになります。
どちらもlenもcapもゼロで、機能的には同じですが、nilスライスの方が望ましいです。

JSONオブジェクトにエンコードする際など、nilではない長さゼロのスライスが好まれることがあることも覚えておきましょう。
[]string{}は空配列にエンコードされますが、nilのスライスはnullにエンコードされます)

インターフェースを設計する際、nilのスライスとnilではない長さ0のスライスに区別を設けることは避けてください。
微妙なプログラミングのエラーを引き起こす恐れがあります。

Goにおけるnilのyより詳しい情報はこちらをみてください

つまり

空のスライスの宣言はvar t []stringを使う方が良い
nilと、nilでは無いが長さ0のスライスとを区別するようなインターフェースは設計しない

Doc Comments

トップレベルのエクスポートされる自明でない型や関数名称にはdocコメントを書いてください。
コメントの規約についての詳細はこちらを参照してください。

Don't Panic

こちらを参照してください。
標準のエラーハンドリングでpanicは使用せず、errorと複数の返り値を用いるようにしてください。

Error Strings

エラー文言は他の文脈に続いて出力される為、頭文字や固有名詞で始まらない限り、大文字を用いたり、句点で終わるべきではありません。
つまりlog.Printf("Reading %s: %v", filename, err)がメッセージの途中で不自然な大文字を使わずにフォーマットされるように、fmt.Errorf("Something bad")ではなくfmt.Errorf("something bad")でコーディングするようにしてください。
これは暗黙的なライン指向で他のメッセージ内に結合されないロギングには適用されません。

つまり

単体で出力されるようなログを除いたエラー文言では、大文字始まりや句読点終わりのメッセージは使用しない

Examples

新しくパッケージを追加する際、実行できる、または完全なコールシーケンスを示す簡単なテストといった、使用例を含めてください。
詳しくはこちら

Goroutine Lifetimes

goroutinesを使用する際は、ライフサイクルを明確にしてください。

goroutinesはチャンネルの送受信をブロックすることで「リーク」することがあります。
ブロックされたチャンネルが到達不可能であっても、ガベージコレクタはgoroutinesを終了させません。

goroutineがリークしていない時でさえ、必要ないにもかかわらず放置していると些細で診断が困難な問題を引き起こす恐れがあります。
閉じたチャンネルでの送信はpanicになります。
使用中の入力を「結果が不要になった後」に編集すると、データの競合を起こし得ます。
goroutineを放置していると予期せぬメモリ使用量になる恐れがあります。

並行コードはgoroutineのライフタイムが明らかになるように、シンプルに記載してください。
それが不可能な時は、いつ・どういった時にgoroutineが終了するのかをドキュメントに記しておいてください。

つまり

goroutineはライフタイムを明確にする
それが無理な時は、いつ・どんな時に終了するのかドキュメントにまとめておく

Handle Errors

こちらを参照ください。
errを_で無視しないでください。
関数がエラーを返す場合、必ずチェックして関数が成功していることを確認して下さい。
エラーハンドルとしては、errを返却して下さい。または完全に例外的な状況であればpanicを使用して下さい。

つまり

エラーチェックはマスト

Imports

名前の衝突を避けるために、importをリネームするのは避けて下さい。
良いパッケージ名はリネームの必要がありません。

import文は空行で区切られた塊で書いて下さい。
標準ライブラリはいつも最初の塊に記載して下さい。

goimportsを用いると自動で実装してくれます。

つまり

importはリネームしないように
goimportsを使ってimport文が秩序だった記載になるようにしよう

Import Blank

Import Dot

In-Band Errors

Indent Error Flow

Initialisms

Interfaces

Goのインターフェースは一般的に、インターフェースの値ではなく、型の値を用いるパッケージに属します。
実装するパッケージは、具体的な(ポインターや構造体の)型を返却するべきです。
そうすることによって、大規模なリファクタ無しで新しいメソッドを追加することができます。

Mockのためのインターフェースを実装するべきではありません。
代わりに、実際に公開されているAPIを使用してテストできるように、APIを実装してください。

使用される前にインターフェースを定義してはいけません。
現実的な使用例無しに、インターフェースの必要性を見極めるのは困難で、どんなメソッドが含まれている必要があるのかを見極めるのが困難であることは言わずもがなです。

【Line Length】

Goコードには厳格な長さの規定はありませんが不快な長さは避けてください。
同様に、長い方が読みやすい際は、行を短くする為に改行を加えるような行為はやめてください。(ex.反復的な文章)

関数の呼び出しや関数の宣言の途中で多かれ少なかれ例外はあるものの、人々が不自然に改行を行っている時、適度なパラメータ数で適度な長さの変数名であれば、改行は必要ないでしょう。
長い行は長い名称が使用されることが多く、その名称を取り除くことが助けになるでしょう。

言い換えれば、基本的には、行の長さではなく書いている内容に基づいて改行を行ってください。
行が長すぎと感じたら、名称や意味を変更して、程よい長さにしてください。

これは実は、関数の長さに対するアドバイスと同じです。
「関数はN行以内」といったルールはありませんが、確かに関数が長すぎる・小さすぎるといった問題はあり、その解決策は行数を数えることではなく境界を変更することです。

つまり

Goでは1行の長さ、関数の行数に関して特に決まりはないけど、極端に長い・短いは避けましょう
意味が崩れないように長い変数名を使用しつつ、行が長くなってしまったら適宜変数名を変更する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む