Go関連のことを調べてみた2022年08月31日

Go関連のことを調べてみた2022年08月31日

Golangで関数にメソッドを生やす

# ある日

関数の型をdefined typeやtype aliasで定義していたとき、ふと思いました。「Golangはdefined typeやtype aliasで型を定義して、その型にメソッドを定義できる。一方関数がファーストクラスオブジェクトな言語であり、関数の型もdefined typeやtype aliasで定義できる・・・、なら関数の型にもメソッドを定義できるのでは?」と :thinking:

# 試してみた

“`golang
package main

import “fmt”

type F func() int

func (r F) Add(i int) F {
return func() int {
return r() + i
}
}

func (r F) Inc() F {
return r.Add(1)
}

func (r F) Calc() int {
return r()
}

func main() {
var f F = func() int { return 1 }
fmt.Printf(“%d\n”, f.Add(

元記事を表示

【Go】Go言語入門①ーGo言語の第一歩

# はじめ

 **Mac** でgo言語を勉強しはじめました。
 自分の成長を記録したいので、記事をアップロードしました。

 macOS Big Sur : 11.6.1

# インストール
HowmebrewでGoをインストールする。
“`
$ brew install go
“`

### バージョン確認
インストールをしてから、バージョンを確認する
“`
$ go version
go version go1.19 darwin/amd64
“`

# goファイルを作成
テストファイル(hello.go)を作成する。
“`
$ touch hello.go
“`

hello.goファイルに下記のソースコードを記入する。

“` go
package main

import “fmt”

func main() {
fmt.Println(“hello world!”)
}
“`
 
編集してから、実行する。

# 実行

## 実行方法1
ビルドして実行する。
“`
$ go build hello.go
“`
同じディレクトリにバイナリデータ(h

元記事を表示

GOLangでフィボナッチ数を計算した

## はじめに
直近Go言語を勉強していますが、なんか数学問題を解けてみまたいため、[フィボナッチ数](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)を計算できるロジックを作成しました。

## 環境
window 10
VSCode

## Target
以下の結果を出力する
“`
フィボナッチ数:(0,1,1,2,3,5…)
“`

簡単に回帰関数を利用して、作りました。

“`go:package.go
package main

import “fmt”

func fibonacci() func(x int) int {
return func(x int) int {
if x < 2 { return x } f := fibonacci() return f(x-2) + f(x-1) } } func main() { f := fibonacci() for i := 0; i

元記事を表示

go installしたバイナリをscratchイメージで動かす場合の注意点

# TL; DR

– webサーバー等netパッケージを使っているバイナリを `go install` する場合は `CGO_ENABLED=0` をつける
– 付けないと `no such file or directory` と出てしまう
– netパッケージをimportしたバイナリはダイナミックリンクでビルドされてしまうのが原因

# はじめに

[gRPC UI](https://github.com/fullstorydev/grpcui) [^1]のバイナリをマルチステージビルドしたら、`no such file or directory` と出て実行できませんでした。

“`bash
$ docker build .
Sending build context to Docker daemon 9.216kB

Successfully built 53b474247144
$ docker run -it –rm 53b474247144
exec ./grpcui: no such file or directory
“`

# 原因

元記事を表示

Go(gin)のAPIテストでテストが止まってしまい終了しない

# はじめに

GoのAPIテストを書いていて問題が発生したのでまとめます
ネットを調べたところ同じ現象が起きていなかったので、初心者の方の参考になればと思います

# 問題

ginで作成したAPIに対してリクエストが200返ってくるか確かめるコードを書いたのですテストが終わらず止まってしまいました

“`go:main.go
package main

var router *gin.Engin

func setupRouter() *gin.Engine {
r := gin.Default()
r.GET(“/ping”, func(c *gin.Context) {
c.String(200, “pong”)
})
r.Run(“:8080”)
router = r
}

func main() {
r := setupRouter()
}
“`

“`go:main_test.go
package main

import (
“net/http”
“net/http/httptest”
“testing”

“github.com/s

元記事を表示

Go(Gin)でfrom-dataをPOSTするテストを書く

# はじめに

最近GoのPOSTに関する記事を挙げていました。
やっと初めて作成したAPIがテスト段階に移り、POSTのテストを書いていたのですがテストでPOSTにどのようにデータを渡すのかに時間をとられたのでまとめます

# 問題

今回はフォームデータをPOSTするテストを書いていました
以下のようなコードを書いたのですが、ginで`c.params`で値を取得しても値がありませんでした
bodyで渡していたのでそれをform-dataで送る必要がありました

“`go:controller_test.go
jsonBody := []byte(`{“content”:”hoge”,”done”:false}`)
req, _ := http.NewRequest(“POST”, “/task”, bytes.NewBuffer(jsonBody))
“`

# 解決方法

以下のようにform-dataを作成してPOSTすることでうまくいきました

“`go:controller_test.go
(省略)
form := url.Values{}
form.Ad

元記事を表示

SQLBoilerで INSERT ON DUPLICATE KEY UPDATE したい

# モチベーション

多くのプロジェクトではレコードを一度で挿入または変更したいという要望があると思います。そんなときDBがMySQLであればBULK INSERTをしたいと思います。ですが、残念ながら今のプロジェクトで用いているSQLBoilerにはBULK INSERTの機能がありません(というか、多くのORMでないと思います)。しかし、SQLBoilerでは独自テンプレートを記述できるため、誰かがやっているだろうということで探すとこちらの記事が見つかりました。

https://qiita.com/touyu/items/4b25fbf12804f12778b7

今のプロジェクトではモデルでIDの生成を行っているため、何も問題なく利用させてもらいました。めでたしめでたし・・・のはずだったのですが、プロジェクトで開発を進めていくうちに、今度は `INSERT ON DUPLICATE KEY UPDATE` に相当する機能が必要となってきました。

せっかくテンプレートを作れて、元々SQLBoilerには`Upsert`があって、先程の記事を見つけたことでBULK INSERTの

元記事を表示

Tagliatelleで構造体のJSONタグのtypoを防ぐ

Go強化月間とのことなので、Go関連の記事を上げていこうと思います。

https://qiita.com/official-events/ae80b010f51f7018891a

# TL; DR

– `Tagliatelle` を [golangci-lint](https://golangci-lint.run/) に設定して、JSONタグをスペルチェックしよう

https://github.com/ldez/tagliatelle

# はじめに

Goで構造体をJSONにmarshal/unmarshalする際、フィールドのタグに対応するキーを指定することが可能です。Goのフィールドは慣習的に `PascalCase` ですが、JSONのキーは `snake_case` にしたいという場合は多いと思います。

“`go
type Person struct {
GivenName string `json:”given_name”`
FamilyName string `json:”family_namae”`
Age int `json:

元記事を表示

Go言語 – Slice / 配列 を for~range で展開してポインタを append すると全部同じ値になる

# 参考

>Goにおいてスライスおよびマップをforで回す際には「rangeで取ってきている値は常に同じメモリアドレスに格納される」ようになっています

https://zenn.dev/canalun/articles/go_for_loop_pointer_trap

後述するが、このせいで一部挙動に問題が出るようだ。

# TL; DR

あまり深く考えずGolangの仕様と割り切ったら良い気がした。

こちらも後述するがループ内で変数を再定義することで回避できる。

# 例

“`go
package main

import “fmt”

func main() {
numbers := []int{1, 2, 3}

for _, number := range numbers {
fmt.Println(number)
fmt.Println(&number)
}
}

// 結果
// 1
// 0xc0000b2000
// 2
// 0xc0000b2000
// 3
// 0xc0000b2000

“`

この例でいうと number

元記事を表示

Go + YouTube Data API v3 で特定のチャンネルの動画データ一覧を取得する

# 目的
YouTube Data API v3を使って、特定のチャンネルにアップロードされた動画に関するデータをすべて取得することが目的です。
APIの仕様上取得できる件数に制限があったり、動画のIDであるVideoIdの一覧を取得する際にちょっと苦労ので、それらを中心に解説していきますが、基本的には以下のリファレンスを見れば、時間はかかるかもしれませんが大体の操作は簡単に実装できるかと思います。
[YouTube API Reference](https://developers.google.com/youtube/v3/docs?hl=ja)

# 前提
* Go言語を使える環境が前提です
* 使っているバージョンは `1.18.3`
* 以下の記事を参考に、YouTube Data API v3を有効にし、APIキーが取得済み
[YouTube Data API v3 を使って YouTube 動画を検索する](https://qiita.com/koki_develop/items/4cd7de3898dae2c33f20)

# 流れ
私のGitHubページに以下の一

元記事を表示

小ネタ/Open API 3.0 ジェネレータ oapi-codegen v1.11.0 のコード自動生成の方法

社内で使う管理用のちょっとした API を OpenAPI & Go(golang) で作るべく **[oapi-codegen](https://github.com/deepmap/oapi-codegen)** を(過去の文献を参考に)使おうとして、

`configuration error: package name must be specified`

に阻まれ、回避方法を探したら **[リリース情報のページ](https://github.com/deepmap/oapi-codegen/releases/tag/v1.11.0)** にちゃんと書いてあった、というだけのメモ書きです。

(ついでにいうと、最初に探し当てていた文献にもちゃんと書いてありました…)

## 以前のバージョンでの使い方

こんな感じで紹介されている例が多かったと思います。

“`sh:
go get github.com/deepmap/oapi-codegen/cmd/oapi-codegen
oapi-codegen 【スキーマ定義の .yaml ファイル】 -package 【パッケ

元記事を表示

【自己学習】Go言語を学ぶ(8)

# 公式チュートリアルから基本を学ぶ
https://go-tour-jp.appspot.com/list

## Switch
switch 文は if – else 文のシーケンスを短く書く方法です。

サンプルコード:実行したOSを調べる

“`go
package main

import (
“fmt”
“runtime”
)

func main() {
fmt.Print(“Go runs on “)
switch os := runtime.GOOS; os {
case “darwin”:
fmt.Println(“OS X.”)
case “linux”:
fmt.Println(“Linux.”)
default:
// freebsd, openbsd,
// plan9, windows…
fmt.Printf(“%s.\n”, os)
}
}
“`

## Switch evaluation order(評価順序の切り替え)
switch caseは、上から下へcaseを評価し

元記事を表示

【自己学習】Go言語を学ぶ(7)

# 公式チュートリアルから基本を学ぶ
https://go-tour-jp.appspot.com/list

## If文

* Go言語の if 文は、先ほどの for ループと同様に、括弧 ( ) は不要で、中括弧 { } は必要です。

サンプルコード:

“`go
package main

import (
“fmt”
“math”
)

func sqrt(x float64) string {
if x < 0 { return sqrt(-x) + "i" } return fmt.Sprint(math.Sqrt(x)) } func main() { fmt.Println(sqrt(2), sqrt(-4)) } ``` 実行結果:1.4142135623730951 2i ## If with a short statement(if文を短くした場合) if 文は、 for のように、条件の前に、評価するための簡単な文を書くことができます。 ここで宣言された変数は、 if のスコープ内だけで有効です。 サンプルコ

元記事を表示

Golang Generics について

# 概要
Golang での Generics に関する知見をまとめた記事になります。

## Generics とは?
> ジェネリック(総称あるいは汎用)プログラミング)は、具体的なデータ型に直接依存しない、抽象的かつ汎用的なコード記述を可能にするコンピュータプログラミング手法である。

Golang では[1.18](https://tip.golang.org/doc/go1.18#language)からGenericsを利用できるようになりました。

**引用元**
– [ジェネリックプログラミング](https://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

# 比較
[公式のドキュメント](https://go.dev/doc/tutorial/generics)を元にGenerics有無のソースコードの比較と書き方を確認します

#

元記事を表示

Windows(WSL2)上にdoodのコンテナを作る

# 最初に結論
これをクローンしてコンテナの中に入ればおk

https://github.com/Mkamono/golang-dood-host-sample

# DooDとは
Docker outsite of Dockerの略です。Docker内部のコンテナからホストのDockerを操作する方法です。DinD(Docker in Docker)という方針もありますが今回はこちらで。
# どうしてそんなことを?
インターンで働いている企業の開発環境がMacです。Docker関連にMakeファイルが用意されており、Dockerコマンド、Goコマンド、Unix系コマンドが必要になったためです。
できるだけローカルの環境を汚さずに開発をしたかったため、Docker上に環境を置きたいと思ったのですが、環境構築の時点でGoのコマンドを使用しているため本来であればローカルにGoをインストールする必要がありました。
DooDを採用することで、ローカルのように扱えるGoのコンテナ、実際に運用しているコンテナの2つによって、擬似的に同じ環境を作ります。

# ディレクトリ構成
“`txt:ディ

元記事を表示

GoでヘッドレスChromeを動かして、ブラウザのLocalStorage取得するメモ

## やりたいこと
とあるサービスをブラウザで開いたときに、ブラウザのlocalStorageに保存されている情報を取り出したい

今回は例としてQiita

## バージョン/パッケージ
* go : 1.17
* chromedp: v0.8.3

## 該当のページをヘッドレスChromeで開くまでのコード

まずは該当のページを開くまで
以下のコードではQiitaのトップ画面のURLをurl変数に入れています。

“`go
package main

import (
“context”
“fmt”
“github.com/chromedp/cdproto/emulation”
“log”
“time”

“github.com/chromedp/chromedp”
)

var userAgent string = “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36”

// 開

元記事を表示

Goの io/fs.FS をOSのファイルシステムにマウントする

# fs.FS内のファイルを他のプロセスに渡したい

Go 1.16 で追加された `io/fs` パッケージで色々なファイルシステムに共通のインターフェイスでアクセスできて便利になりました.この`fs.FS`の中身にシェルやエクスプローラからアクセスして操作できると便利そうです.

例えば,ネットワークストレージのクライアントを Go で実装する場合 `fs.FS` インターフェイスを実装すると思いますが,そのクライアントをそのままマウントできれば他のアプリケーションからデータにアクセスできます.

# GoでFUSEを使う

大抵の環境では,ユーザプログラムがファイルシステムを提供するためのFUSEという仕組みが使えます.

Linuxの場合は,[go-fuse](https://github.com/hanwen/go-fuse) というbindingsがあります.

https://github.com/hanwen/go-fuse

専用のインターフェイスを提供する必要があってfs.FSを使うのは少し面倒ですが,高機能かつ活発に開発が続いています.

Windowsの場合は,

元記事を表示

Go言語~deferについて~

こんちには!
LIFULLエンジニアの吉永です。

本日はGoのdeferについて、コードレビューしていて「あれ?これどう動くんだろう?」ってちょっと判断に迷ったdeferの記述方法があり、改めてdeferについてと、Go Playgroundで動作確認した結果をまとめました。
※[Go 強化月間](https://qiita.com/official-events/ae80b010f51f7018891a)を開催中らしいです!

## deferとは?

### deferの公式ドキュメント

https://go.dev/ref/spec#Defer_statements

### 特徴
遅延実行の為の仕組みで、JavaやC#など多数のプログラミング言語で採用されているtry~catch~finallyのfinallyと似たようなものですが、単純比較すると下記のような特徴を持ちます。

– return時だけでなく、panic時にも実行される。
– 一つのブロック内に複数のdefer定義が可能。
– deferで定義された処理はLIFO(Last In First Out)で実行さ

元記事を表示

【#55 エンジニア転職学習】Goでスクレイピングプロジェクト(完成)

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

間隔が空いてしまいましたが、
スクレイピングのプロジェクトが一旦完成しました。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。

https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容

* **Goで求人情報のスクレイピング ←Topics!!**

# Goで求人情報のスクレイピング
前回から取得したURL一覧の各求人情報を取得してくる機能、
その情報をMySQLからCSVファイルにエクスポートする機能を追加しました。

各ファイルのおおまかな役割は以下になります。
“`
job_offer_scraping/
├── main.go –> DBコネクタ起動、スクレイピング、CSV出力実行
├── csv
│ └── csv.go –> MySQLのmynavi_jobsテーブルから

元記事を表示

Goでerrors.New()の値を比較するテストでイコールにならない

# はじめに

Goを始めたばかりでAPIを一つ作成してテストに挑戦したところかなり沼ってしまいました
原因を解明するのにかなり時間がかかってしまったので初心者のためにまとめます
自分が探していた情報がある記事がなかったので(仕組みを知っているならあたりまえの理由だった)、役に立てばと思います

# 問題

“`go:main.go
package main

import (
“errors”
“fmt”
)

func main() {
err1 := errors.New(“error”)
err2 := errors.New(“error”)

fmt.Println(err1 == err2)
}
“`

この結果が`false`になってしまうのが理解できずにテストでも同じような比較をしていたのでテストが通らず困りました

# 解決方法

これは`errors.New`の処理をみれば納得できます

“`go
func New(text string) error {
return &errorString{text}
}

// errorString is

元記事を表示

OTHERカテゴリの最新記事