2020/04/04


Go でスライスに挿入する例として Go の Wiki に以下の物が記載されている。

しかしこのコードは、挿入されるスライスから部分スライスを取り出し、そこに挿入するスライスを append に割り当てる為に展開し、さらに残りの部分スライスも append に割り当てる展開を行っている。なので実装コードとしては短いが、実際に実行されるオペレーションコードが冗長になる。また、スライスの伸長はおよそ2倍ずつ増える。なので例えば 5000 個のスライスに 1000 個のアイテムを挿入すると、キャパシティはおよそ 12000 近くになる。Go ではこういったスライスの操作も、基本的には自身で make によりメモリを確保し、ループで値を割り当てるのが良い(面倒かもしれないがその方がメモリも節約され速い)とされている。

以下、ベンチマークを取ってみる。

package main_test

import (
    "reflect"
    "testing"
)

type T int

func BenchmarkAppend(b *testing.B) {
    b.ResetTimer()

    input := make([]int5000)
    for i := 0; i < 5000; i++ {
        input[i] = i
    }
    insert := make([]int1000)
    for i := 0; i < 1000; i++ {
        insert[i] = i
    }
    expected := make([]int6000)
    for i := 0; i < 6000; i++ {
        if i < 1000 {
            expected[i] = i
        } else if i < 2000 {
            expected[i] = i - 1000
        } else {
            expected[i] = i - 1000
        }
    }
    n := 1000
    var output []int

    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        output = append(input[:n], append(insert, input[n:]...)...)
    }
    b.StopTimer()
    if !reflect.DeepEqual(output, expected) {
        b.Fatal("bad insertion")
    }
}

func BenchmarkNormal(b *testing.B) {
    input := make([]int5000)
    for i := 0; i < 5000; i++ {
        input[i] = i
    }
    insert := make([]int1000)
    for i := 0; i < 1000; i++ {
        insert[i] = i
    }
    expected := make([]int6000)
    for i := 0; i < 6000; i++ {
        if i < 1000 {
            expected[i] = i
        } else if i < 2000 {
            expected[i] = i - 1000
        } else {
            expected[i] = i - 1000
        }
    }
    n := 1000
    var output []int

    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        output = make([]intlen(input)+len(insert))
        for l := 0; l < n; l++ {
            output[l] = input[l]
        }
        for l := 0; l < len(insert); l++ {
            output[l+n] = insert[l]
        }
        for l := n; l < len(input); l++ {
            output[l+len(insert)] = input[l]
        }
    }
    b.StopTimer()
    if !reflect.DeepEqual(output, expected) {
        b.Fatal("bad insertion")
    }
}

func BenchmarkCopy(b *testing.B) {
    input := make([]int5000)
    for i := 0; i < 5000; i++ {
        input[i] = i
    }
    insert := make([]int1000)
    for i := 0; i < 1000; i++ {
        insert[i] = i
    }
    expected := make([]int6000)
    for i := 0; i < 6000; i++ {
        if i < 1000 {
            expected[i] = i
        } else if i < 2000 {
            expected[i] = i - 1000
        } else {
            expected[i] = i - 1000
        }
    }
    n := 1000
    var output []int

    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        output = make([]intlen(input)+len(insert))
        copy(output, input[:n])
        copy(output[n:], insert)
        copy(output[n+len(insert):], input[n:])
    }
    b.StopTimer()
    if !reflect.DeepEqual(output, expected) {
        b.Fatal("bad insertion")
    }
}
BenchmarkAppend-8          42700             26185 ns/op
BenchmarkNormal-8          70170             18005 ns/op
BenchmarkCopy-8            90902             15787 ns/op

Wiki に載っているコードは、手動でスライスを挿入するコードの1.5~2倍遅い。copy を使うともう少し速い。

みんなのGo言語[現場で使える実践テクニック] みんなのGo言語[現場で使える実践テクニック]
松木雅幸, mattn, 藤原俊一郎, 中島大一, 牧大輔, 鈴木健太
技術評論社 Kindle版 / ¥2,178 (2016年09月09日)
 
発送可能時間:今すぐダウンロードできます。

Posted at by



2020/02/27


こういった場合に便利なのがオフィシャルが提供している解析コマンド shadow です。(相変わらずググらび...)

インストールは以下を実行します。

$ go get golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow

ツイートされておられる以下のコードで実行してみます。

package main

import (
    "fmt"
)

var condition = true

func main() {

    var hoge *string
    if condition {
        hoge, err := do("word")
        if err != nil {
            return
        }
        fmt.Printf("checkpoint: %v\n", *hoge)
    } else {
        hoge = nil
    }

    fmt.Printf("RESUT: %v\n", hoge)

}

func do(v string) (*stringerror) {
    return &v, nil
}
.../main.go:13:3: declaration of "hoge" shadows declaration at line 11

便利。

改訂2版 みんなのGo言語 改訂2版 みんなのGo言語
松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太
技術評論社 Kindle版 / ¥2,278 (2019年08月01日)
 
発送可能時間:

Posted at by



2020/02/25


執筆者様に Twitter でお声掛け頂き、発売前ながら献本頂く事になりました。執筆された森下様、送付頂いた技術評論社様、ありがとうございました。

Visual Studio Code実践ガイド —— 最新コードエディタを使い倒すテクニック Visual Studio Code実践ガイド —— 最新コードエディタを使い倒すテクニック
森下 篤
技術評論社 Kindle版 / ¥2,905 (2020年02月21日)
 
発送可能時間:

Visual Studio Code は登場から色々な機能を取り込みつつ着実にユーザを増やし、統合開発環境としては今や飛ぶ鳥を落とす勢いになった言って良いでしょう。以下は 2019 年の Stackoverflow Survey で公開された有名な開発環境の調査結果です。

StackOverflow Survey 2019

僕は普段は Vim というテキストエディタを使っていますが、実は僕は色々なテキストエディタを試します。Emacs も人並み程度使えますし、Visual Studio Code も拡張を自分で書いた事がある程度には使っています。

Search results - mattn | Visual Studio Code , Visual Studio Marketplace

...

https://marketplace.visualstudio.com/search?term=mattn&target=VSCode&category=All%20categories&sortBy=Relevance

正直に言うと、Visual Studio Code が登場後しばらく経ってから端末表示機能を実装した時に、少しだけ悔しくて同時期に Vim の作者 Bram Moolenaar 氏が「端末機能を足そう」と言い出した時には誰よりも早く、そして Bram Moolenaar 氏による UNIX の実装よりも早く Windows のパッチを送った事を覚えています。そして個人的には今も尚、Visual Studio Code は良い目標の1つだと思っています。

本書は Visual Studio Code を知らない開発者が Visual Studio Code を使いこなせる様になるまでに、机の片隅に置いておくと便利な一冊となるでしょう。各ツールバーやコマンドパレット、Visual Studio Code での Git の扱い方、デバッガの使い方、拡張のインストールや拡張の作り方、Visual Studio Code を使った TypeScript 開発の実例を交えた説明、Go 開発の実例を交えた説明、多くの方がマッチしそうな内容になっています。本書を片手に写経しながら読み進めたならば、おそらく Visual Studio Code をあまり触った事が無かった方でも読み終わる頃には使いこなせる様になっているのではないかと思います。

僕は Visual Studio Code が登場した当初から Visual Studio Code を使っていますが、それでも知らない内容が沢山書かれていました。Visual Studio Code には自分が扱う言語拡張しかインストールしていなかったので、Visual Studio Code が扱えるデバッガ多さを紹介した画面キャプチャには驚きました。またデバッガの設定情報が書かれている launch.json で console や useWSL といった項目があり、それらを使ってもっと便利にデバッグできる事も知りました。とても勉強になりました。

一番の収穫は、特定のワークスペースでのみ拡張を有効にする為の設定でした。この辺りを知りたい方は、ぜひ購読してみるのが良いと思います。

本書で1点、惜しいなと思う事をあえて言うとすれば索引が若干少ない所だと思います。400ページを超えるこれだけのボリュームで内容も程よく濃いので、後から読み返したくなる事は間違いなくあると思います。そんな時に索引から読みたい箇所に戻れるととても便利だろうなと思いました。個人的に特に良かったなと思ったのが Visual Studio Code を使っての todo アプリ開発を TypeScript と Go の両方で実践している章でした。これらはこれから実務で統一的に Visual Studio Code を使って行こうとされておられる企業の方々には良い教科書になりえると思いました。

ところで最近、Vim の Language Server 事情も少し変化があり、vim-lsp-settings という、Language Server Client である vim-lsp のサポートを行うプラグインを作っています。多くの Language Server を Visual Studio Code 並みに簡単にインストールする事ができる様になっています(coc よりも多いです)。直近では Visual Studio Code の様にプロジェクト専用設定を行う事もできる様になったので、ワークスペース専用にデータベース接続先を設定する事も可能です。lighttiger2505 さんが開発しておられる SQL の Language Server、sqls も簡単にインストールする事ができます。さらに efm-langserver という汎用の Language Server との連携も便利です。tsuyoshicho さんが作ってくれている vim-efm-langserver-settings を入れるとインストールされているツール類を linter として多くのフォーマットのエラーをチェックする事が出来る様になっています。こういった Language Server に関するアイデアはエディタの垣根を越えて共有される、とてもフェアな良い技術の進歩であり僕もやっていて楽しいです。これからも Visual Studio Code に追いつける様に頑張っていきたいと思います。

今後も、Visual Studio Code と気持ちよい技術的な競争ができるといいなと本書を読んで改めて思いました。

Posted at by