20210115のGoに関する記事は3件です。

GoでDropbox API v2を使ってみる

タイトルの通り、DropboxAPIを使ってみました。

手始めにgo getする

go get github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/...

ファイルをアップロードするサンプルコード

インスタンスを作って、ファイルをアップロードする処理となっています。

import "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox"
import "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/users"

func main() {
    config := dropbox.Config{
        Token: "<取得したアクセストークン>",
    }
    dbx := users.New(config)

    req := files.NewCommitInfo("<ファイルのアップロード先>")
    f, _ := os.Open("<アップロードしたいファイルのパス>")
    _, err := dbx.Upload(req, f)
    if err != nil {
        log.Print(err)
        return
    }
}

Dropbox APIのアクセストークンを取得する

以下のサイトから登録してアクセストークンを取得しました。
https://www.dropbox.com/developers

実行してみたが、、、

上手くいきませんでした。
「missing_scope」というメッセージが出ていて調べてみたところ、権限が不足していました。
デフォルトで権限が追加されていない、Dropboxのファイルとフォルダーのコンテンツを編集するためのfiles.content.writeを追加して再度実行したらうまくいきました。

image.png

僕が詰まったところ

当たり前かもしれませんが、権限を追加した後はアクセストークンを再発行する必要があります。皆さんも気を付けてください。

感想

LINE Bot に送信した画像をDropboxに保存するシステムを作ろうと思います。

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

Go言語チートシート

概要

goを書いていてよく使う割によく忘れる処理まとめ
思い出したら順次書き足します

Context

https://pkg.go.dev/context

コンテクストは環境やスコープ、タイムアウトなどをツリー式に管理する構造体。
goを書く上で非常に重要な概念です。

import (
    "context"
)

ctx := context.Background()

ctx, cancel := context.WithCancel(ctx)
defer cancel()

store

package main

import "context"
import "log"

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "silly", "work")

    value := ctx.Value("silly")
    // 返り値はinterface{}なので値のキャストが必要
    str, ok := value.(string)
    if !ok {
        log.Println("value not found")
    }

    log.Printf("value found: '%s'", str)

    // 上の省略形がこれ
    str, ok = ctx.Value("silly").(string)
    log.Printf("re value found: '%s'", str)
}

タイムアウト処理

package main

import (
    "context"
    "time"
    "log"
)

func main(){
    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, time.Second * 1)
    defer cancel()

    go func(){
        // too many time function
        time.Sleep(time.Second * 10)
    }()

    <-ctx.Done()

    log.Println("done")
}

環境変数

参照する変数が少数なら普通にos.Getenv()を使えばいい。

import "os"

debug := os.Getenv("DEBUG")

DB設定のように、デフォルト値や必須値が欲しい場合はhttps://github.com/caarlos0/env/ を使うと便利

package main

import (
    "log"

    "github.com/caarlos0/env/v6"
)

type DatabaseConfig struct {
    UserName string `env:"DB_USER,required"`
    Password string `env:"DB_PASSWORD,required"`
    Host     string `env:"DB_HOST" envDefault:"localhost"`
    Port     string `env:"DB_PORT" envDefault:"3306"`
    DBName   string `env:"DB_NAME"`
}

func main() {
    cfg := new(DatabaseConfig)

    if err := env.Parse(cfg); err != nil {
        log.Printf("%+v\n", err)
    }

    log.Printf("%+v\n", cfg)
}

JSON

package main

import "encoding/json"

type Valiable struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}

func load(obj []byte) (*Valiable, error) {
    valiable := new(Valiable)
    err := json.Unmarshal(obj, valiable)

    return valiable, err
}

func dump(valiable *Valiable) ([]byte, error) {
    return json.Marshal(valiable)
}

func main() {
    object := []byte(`{"key": "egg", "value": "spam"}`)

    // to struct
    valiable, _ := load(object)

    // to []byte
    obj, _ := dump(valiable)

    _ = obj
}

io

ファイル読み出し

package main

import (
    "os"
    "log"
    "io/ioutil"
)

func main() {
    file, err := os.Open("test.bin")
    if err != nil {
        // no such file やら permission errorやら
        // このハンドリングを省略するとロクなことがない
        log.Fatal(err)
    }
    // このタイミングでクローズのdeferを書いておく
    defer file.Close()

    // すべてを[]byteで読み出す荒業
    b, err := ioutil.ReadAll(file)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(b)


    /// open からReadallまでの流れを全部やってくれるすごいやつ
    content, err := ioutil.ReadFile("test.bin")
    if err != nil {
        log.Fatal(err)
    }
    log.Println(content)
}

log

https://pkg.go.dev/log
https://pkg.go.dev/fmt

標準出力はfmtを使う例が多いが、スレッドセーフではないためgoroutinを多用すると出力が混ざる可能性がある。
実運用する場面ではlogを使ったほうが無難ではある

package main

import (
    "errors"
    "log"
)

func main() {
    log.Println("spam")                     // 2021/01/19 18:47:35 spam
    log.Println("egg", "bacon", "and spam") // 2021/01/19 18:51:04 egg bacon and spam

    // Printfはfmtと同じ
    log.Printf("I'm a %s It's Ok", "Lumberjack") // 2021/01/19 19:53:54 I'm a Lumberjack It's Ok
    log.Printf("int: %d", 253)                   // 2021/01/19 19:51:39 int: 253
    log.Printf("hex: 0x%x", 253)                 // 2021/01/19 19:51:39 hex: 0xfd
    log.Printf("oct: 0o%o", 253)                 // 2021/01/19 19:51:39 oct: 0o375
    log.Printf("bin: 0b%b", 253)                 // 2021/01/19 19:51:39 bin: 0b11111101

    s := struct {
        ID   int
        Name string
    }{123, "Graham"}

    // 構造体のダンプ時に便利
    log.Printf("%+v", s) // 2021/01/19 19:50:00 {ID:123 Name:Graham}

    log.SetPrefix("[log] ")
    log.Println("プレフィックスをつける") // [log] 2021/01/19 18:50:07 プレフィックスをつける
    log.SetPrefix("")

    log.SetFlags(log.Flags() | log.LUTC)
    log.Println("時刻タイムゾーンはデフォルトを使用するが、フラグを追加することによりUTCにできる") // 2021/01/19 09:57:09 時刻タイムゾーンはデフォルトを使用するが、フラグを追加することによりUTCにできる

    log.SetFlags(0)
    log.Println("フラグをすべて外すと時間出力をオフにできる") // フラグを設定すると時間表示をオフにできる

    log.SetFlags(log.Ldate | log.Lmicroseconds)
    log.Println("マイクロ秒まで表記") // 2021/01/19 18:57:09.086480 マイクロ秒まで表記

    log.Fatal(errors.New("何かしらのエラー")) // エラー内容を出力してstatus code 1で終了する
}

panic

package main

import (
    "log"
)

func main() {
    defer func() {
        e := recover()
        if e != nil {
            str, _ := e.(string)
            log.Println("panic:", str)
        }
    }()

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

【自己学習用】はじめてのGo1

参考元

Markdown記法 チートシート
Markdown記法 サンプル集
Qiita Markdown 書き方 まとめ
qiitaに書くのは初めてなのでMarkdown記法もついでに学習。
はじめてのGo

Go言語の特徴

  • 2009年にGoogleにより発表されたオープンソースのプログラミング言語
  • シンプルな言語仕様であるため学習が比較的容易
  • 豊富な標準パッケージが同梱されている
  • 巨大なコードでも高速にコンパイルできる
  • Windows,OS X,Linuxなどの環境に合わせた実行ファイルを生成するクロスコンパイルのしくみがある
  • 並行処理のサポートも充実しており,ミドルウェアの開発などにも適している

言語仕様について

  • 他の言語が持つような機能の多くを削り、言語をシンプルに保っている
  • 繰り返し構文はfor文しかなく,while文やdo/while文などはサポートされていない
  • ifの波括弧は省略できず,三項演算子もない:thumbsup:
  • ポインタなし
  • 暗黙の型変換なし
  • 宣言されたものの使われていない変数があるとコンパイルが通らない
  • 例外(try/catch構文)がない。発生した異常を戻り値として呼び出し側に返す方針

インストール

はじめてのGoに従って進めていきます。
インストーラ
1.png
msiファイルをダウンロード→実行。
全部デフォルトでOK。
WS000010.JPG

コマンドでver確認。

$ go version
go version go1.15.6 windows/amd64

hello world

hello.goを作成。
環境はとりあえずVSCODE。

package main

import (
    "fmt"
)

func main() {
    fmt.Println("hello world")
}

作成したフォルダにcdして実行。

$ go run hello.go
hello world

helloされた。

コンパイル

go buildでコンパイル。
exeファイルができる。

$ go build hello.go

フォーマット

go fmtでフォーマット。
Goでは,標準のコーディング規約があるのでそれに従ってフォーマットされる。
半角スペース派とタブ派の永遠の争いはgoでは起きない。

$ go fnt hello.go

Goのプロジェクト構成とパッケージ

共通のファイルを使用するためにはGOPATH以下にファイルがないと認識されない。

まず,myprojectディレクトリを起点に,次のようにbin,pkg,srcという3つのディレクトリを作成します。
次に,myprojectディレクトリのパスをGOPATHという環境変数に指定します。

とあるがインストール時に環境変数がユーザ\go以下に設定されているので
それをそのまま使うことにする。環境変数変更するのはなんかやだし。

gosampleパッケージ

ユーザ\go\src\gosample\gosample.goを作成する。

package gosample

var Message string = "hello world"

mainパッケージ

任意の場所(自分はgithub管理フォルダ)/myproject\src\main/main.goを作成する。

package main

import (
    "fmt"
    "gosample"
)

func main() {
    fmt.Println(gosample.Message) // hello world
}

ビルドと実行

$ cd myproject\src\main
$ go run main.go

go installコマンドを用いると,生成されたファイルが$GOPATH/binに自動的に格納される。

$ cd ユーザ\go\src\main
$ go install

ここまでの成果物は以下にUP。
https://github.com/yusuke-nomura-cosmoroot/GoStudy

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