20210510のGoに関する記事は7件です。

Goのnew()とmake()の違いと、それぞれの使い所をさらっとまとめる

new() new(T)はtypeがTのインスタンスを、Tのゼロ値で生成して、そのポインタを返してくれる。 構造体でよく使われる。 make() make(T, args)における、Tはsliceかmapかchannelのいずれかである。 make(T, args)はtypeがTのインスタンスをargsを元に初期化して返してくれる。 new()とmake()の使い分け そもそも、make()はsliceかmapかchannelでしか使えない。 これら3つの型には初期化情報を与えることで事前にメモリを確保しておくことが可能だ。 sliceにはlenとcapを、mapとchannelにはlenを与えられる。 あらかじめ使用するメモリ幅が決まっているのなら事前に確保しておくことで、処理時間を短くできる。 一応、new()でsliceやmapのインスタンスを生成することもできる。 package main import ( "fmt" ) func main() { s := new([]string) (*s) = append((*s), "hello") fmt.Println((*s)[0]) // output: hello } package main import ( "fmt" ) func main() { m := new(map[string]string) m = &map[string]string{} // この行がないとエラーになる (*m)["hello"] = "world" fmt.Println((*m)["hello"]) // output: hello } ご覧の通り、sliceとmapのゼロ値はnilであったり、new()がポインタを返すせいで、冗長な書き方になってしまう。 処理を短時間にする観点に加えて、sliceやmapやchannelでは初期化情報を与えないとすぐに使えないという事情もありそうだ。 new()の使い所はというと、sliceでもmapでもchannelでもない型のインスタンスを生成したい時、ということになる。 ただ、それらは初期化子としてリテラルが使えることがほとんどだ。 package main import ( "fmt" ) func main() { str := new(string) *str = "hello" fmt.Println(*str) } ?このように書くよりも、 ?このように書いた方が早い。 package main import ( "fmt" ) func main() { str := "hello" fmt.Println(str) } ということなので、new()の使い所はある程度限られてきそうだ。 使い所の一つにはゼロ値の初期化で十分使える状態になるという場合がある。 type SyncedBuffer struct { lock sync.Mutex buffer bytes.Buffer } p := new(SyncedBuffer) sync.Mutexのゼロ値はUnlockedなmutexで、 bytes.Bufferのゼロ値は、すぐに使える空のバッファーである。 これはゼロ値が便利なのでnew()を使いたい。 もう一つには、構造体をnew()で初期化しておいて、メンバを一つずつ計算して当てはめていきたい場合もあるかもしれない。 また、構造体で、ほとんどのメンバのゼロ値は使えるが、一部のメンバのゼロ値はやっかいな場合に、とりあえずnew()してから一部のメンバを計算するという使い方もできそうだ。 まとめ Effective Goにはこう書かれている。 "Since the memory returned by new is zeroed, it's helpful to arrange when designing your data structures that the zero value of each type can be used without further initialization. " ゼロ値がすぐに使えるもので、追加の初期化処理がいらないときにnew()を使うと便利だよ、ということらしい。 これからは立ち止まって初期化の方法を考えていきたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Adjust のリアルタイムコールバックを Cloud Logging に流す

1. はじめに Adjust のリアルタイムコールバックを利用すると、 Adjust の計測結果を指定のサーバーに送信する事ができます。 この記事では、 Adjust のデータを Cloud Functions に送信して Cloud Logging へ流すための設計をまとめます。 2. アーキテクチャ Adjust でリアルタイムコールバックを利用する際、受け口となるサーバーが必要となります。 今回は Cloud Logging へ送る事が目的なので、同じ GCP の Cloud Functions を使います。 アーキテクチャの完成予想図はこちらです。 3. サーバーを建てる アーキテクチャで記述した通り、サーバーには Cloud Functions を利用します。 以下のパラメータで Cloud Functions を作成します。 Cloud Functions の設定 項目 設定内容 関数名 adjust-server リージョン asia-northeast1 トリガーのタイプ HTTP 認証 認証が必要 ランタイム Go 1.13 エントリポイント GetRawData Cloud Functions は複数言語のランタイムに対応していますが、今回は Go 1.13 で実行します。 ログの出力は構造を変更しやすいように uber-go/zap を利用します。 package p import ( "fmt" "net/http" "go.uber.org/zap" ) var zlogger *zap.Logger func init() { var err error zlogger, err = zap.NewProduction() if err != nil { fmt.Printf("request parse failed. %v", err) return } } func GetRawData(_ http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { fmt.Printf("request parse failed. %v", err) return } fields := make([]zap.Field, 0, len(r.Form)+1) fields = append(fields, zap.Namespace("body")) for k, v := range r.Form { fields = append(fields, zap.String(k, v[0])) } zlogger.Info("AdjustLogger", fields...) } デプロイが完了したらトリガーURLを叩いてみましょう。 $ curl https://asia-northeast1-${project_id}.cloudfunctions.net/adjust-server クエリパラメータを追加して叩くと、パラメータ情報もログとして出力されます。 ​ 4. Adjust のリアルタイムコールバック設定 Adjust 側で行う設定は以下の公式ドキュメントに書かれています。 データの管理 > ローデータエクスポート > リアルタイムコールバック 抜粋すると、以下の手順で設定できます。 ① 該当アプリの下部に表示されている(▲)ボタンを選択します。 ② その他の設定 (All Settings)​> ローデータエクスポート (Raw Data Export)​ > リアルタイムコールバック (Real-Time Callbacks)​を選択します。 ③ グローバルコールバック(GLOBAL CALLBACK)​を選択する。 ④ コールバックURLを入力します(コールバックURLのテンプレートおよび推奨のプレースホルダーを参照)。 ⑤ UPDATE​を選択します。 今回は例としてグローバルコールバックを使用します。 コールバックURLは、先ほど作成した Cloud Functions のトリガーURLに必要なクエリパラメータを追加したURLになります。 https://asia-northeast1-${project_id}.cloudfunctions.net/adjust-server?app_id={app_id}&app_name={app_name} app_id, app_name 以外の情報が欲しい場合は Adjust Placeholders にプレースホルダーのドキュメントがあるので、必要なクエリパラメータを探して設定して下さい。 ​ コールバックURLが設定できたら Adjust のイベントを発火させてみましょう。 正しく疎通できていれば以下のようなログが Cloud Logging に出力され、 jsonPayload.body の中にプレースホルダーの情報が表示されます。 { "insertId": "000000-...", "jsonPayload": { "msg": "AdjustLogger", "body": { "app_id": "foo", "app_name": "bar" }, "level": "info", "caller": "serverless_function_source_code/function.go:33", }, "resource": { "type": "cloud_function", "labels": { "project_id": "xxx", "function_name": "adjust-server", "region": "asia-northeast1" } }, ... } 5. IP 制限をかける これまでの設定で、 Adjust から送られるリアルタイムコールバックの情報を Cloud Logging に流すことができました。 ただ、今のままだと外部から指定のURLに直接アクセスできるので Adjust 以外の情報が混入する可能性があります。 この問題を解決するため、 Cloud Armor で Adjust の IP をホワイトリストに設定します。 Cloud Functions の設定を変更する まずは作成した Cloud Functions リソースを外部からアクセスできないようにします。 adjust-server の編集を行い、 ランタイム、ビルド、接続の設定 > 接続 > 内部トラフィックと Cloud Load Balancing からのトラフィックを許可する を設定して更新しましょう。 正しく更新されると、トリガーAPIを叩く際に403エラーが返るようになります。 Cloud Load Balancing を作成する 次に、 Cloud Load Balancing を作成します。 以下の手順でロードバランサーの設定画面に移動します。 Cloud Load Balancing > ロードバランサを作成 > HTTP(S)負荷分散 インターネット接続の設定は インターネットから自分のVMへ を選択します。 ロードバランサーの名前は 「adjust-server-lb」 としましょう。 Cloud Load Balancing を作成するためには、バックエンドとフロントエンドの設定をする必要があります。また、今回は Cloud Functions のエンドポイントを設定するため、サーバーレス NEG を設定する必要があります。 バックエンド、フロントエンド、サーバーレス NEG を以下のように設定し、 Cloud Load Balancing を作成します。 バックエンドの設定 項目 設定内容 名前 adjust-server-backend バックエンドタイプ サーバーレスネットワークエンドポイントグループ プロトコル HTTP タイムアウト 30秒 バックエンド adjust-server-neg (新規作成) セキュリティ なし サーバーレス NEG の設定 項目 設定内容 名前 adjust-server-neg リージョン asia-northeast1 サーバーレスネットワークエンドポイントグループの種類 Cloud Functions 関数名を選択 adjust-server フロントエンドの設定 項目 設定内容 名前 adjust-server-frontend プロトコル HTTP ネットワークサービス階層 プレミアム IPバージョン IPv4 IPアドレス エフェメラル ( or 静的IPアドレス) ポート 80 Cloud Load Balancing リソースが作成されたら、作成された IP アドレスにアクセスしてみましょう。 Cloud Functions のトリガーURLにアクセスした時と同様にログが出力されていればOKです。 $ curl http://${lb_ip_address} Cloud Armor のポリシーを作成する 最後に、 Cloud Armor で Adjust の IP アドレスをホワイトリストに登録します。 Cloud Armor > ポリシーを作成 から、ポリシーの設定を行います。 Adjust の IP アドレスは以下の公式ドキュメントを参照してください。 参考資料 > リスト > Adjustサーバー IP ポリシーの設定 項目 設定内容 名前 adjust-server-policy デフォルトのルールアクション 拒否 拒否ステータス 403 (アクセス拒否) 関数名を選択 adjust-server ルールの追加 項目 設定内容 モード 基本モード 一致 x.x.x.x/24,x.x.x.x/24,... アクション 許可 優先度 0 ※ IPアドレスは最大で10個までしか指定できないので、複数のルールを追加します。 ※ 優先度は重複できないので、新しいルールを追加する際は優先度をインクリメントしてください。 ターゲットへのポリシーの適用 項目 設定内容 タイプ ロードバランサ バックエンドサービス ターゲット adjust-server-backend ポリシーが作成されたら、ロードバランサーのセキュリティ設定にadjust-server-policyを追加します。 Cloud Load Balancing から adjust-server-lb の編集画面に遷移します。 バックエンドの構成 から adjust-server-backend を選択し、 セキュリティ に adjust-server-policy を設定します。 これで Cloud Functions へのアクセスを Adjust の IP からのみ許可する設定ができました。 Adjust のコールバックURLを変更する 各リソースの作成が完了したら、 Adjust のリアルタイムコールバックの設定を更新しましょう。 http://${lb_ip_address}?app_id={app_id}&app_name={app_name} 今回は省略していますが、運用する際は以下の設定もやっておくと良いでしょう。 Cloud DNS を使ってドメインを設定する 静的 IP を取得してロードバランサーのフロントエンドに設定する SSL/TLS 通信の設定 6. まとめ Adjust のデータを Cloud Functions に送信して Cloud Logging へ流すための設計をまとめました。 簡易的に作るだけであれば Cloud Functions を使うだけで良いですが、実戦運用する際には IP 制限や負荷分散を考慮する必要があるので、 Cloud Load Balancing や Cloud Armor を併用する設計が良いと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アスキーアートコンパイラを作りました

はじめに アスキーアートというのを皆さんはご存知でしょうか? 文字だけで構成されたイラストや画像のようなものです。 例 --------------------------------------- |acsc file (The ASCII Art Source Code)| --------------------------------------- | |ASCII Art Compiler(acc) output | |------------|-----------| | | | | | | |---------- |--------- |--------- |HTML File| |png File| |pdf File| ----------- ---------- ---------- しかし、これだけだと、単なるテキストファイルです。 これを画像ファイルをはじめとする様々な形式に変えたいと思いました。 成果物 ASCII_art_compiler そこでGoでアスキーアートコンパイラというツールを作りました。 これを使えば、先ほどのアスキーアートを画像やPDF、HTMLファイル等に変換することができます。 さらに、プロジェクト管理機能もあるため、設定ファイルを変えるだけでフォントサイズ等を変更できます。 チュートリアル mkdir your-project cd your-project acc new mv /favorite.ttf ./font/font.ttf #好きなフォントデータをお使いください でプロジェクトを作成します。 好きなエディタでアスキーアートを書いてください。 nvim main.aasc 出力したい場合はビルドで出力することができます。 acc build --type image # 画像ファイルを出力 詳しくはReadme.mdをご覧ください。 一番上のアスキーアートを画像として出力した場合
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Go Unity React] 3Dでライフゲームを試せるサイト作りました

はじめに ライフゲーム(海外だとGame of Life)という生物学的モデルシュミレーションを3次元で作成してみました。 サーバーサイド Golang, クライアントUnity & React使用です。 ゲームリンク↓ そもそもライフゲームとは 聞いたことのない方が多いと思いますが、ライフゲームとは格子を生命とみなしたモデルシュミレーションです。 ユーザー自身がルールを定めてどのような生命活動が行われるかシュミレーションすることができます。 基本的には「縦 × 横」の二次元で作成されることが多いですが、 今回は「高さ」を加えた三次元で作ってみました! ゲーム詳細 ゲームリンクはこちらです。 アピールポイント いい感じに生命循環が見られたモデルを保存できるようにしたところ 他ユーザーが作成したモデルにいいねを付けられるようにして、ランキングの高いモデルマップを実際に動かせるようにしたところ ユーザーがシュミレーションを楽しめるようにするため、生命活動のルール変更や、ステージ編集をできるようにしたところ 使用技術 アーキテクチャ図 サーバーサイド系 環境 docker Golang version1.16.2 postgres, heroku GitHubです↓ 綺麗な依存関係を意識してアーキテクチャを組みました。 こちらのgo-clean-archを参考にしています。 DIツールのwireを入れました。また、Postgresを使った理由としてはherokuの無料枠が優秀だったからです。 クライアント系 環境 Unity version2019 JavaScript(react) Vercel(デプロイ先) GitHubです↓ ゲーム部分はUnityで、 webGLビルドしたファイルをreactコンポーネントとして使用できるreact-unity-webglを使いました。 Javasciptでunityの関数も動かすことができるので非常に便利なライブラリだと思います。   頑張ったこと 無料枠を意識した herokuやVercelを利用してなんとか全部無料で永続化できました。 ユーザーがモデルを保存できるところ 3Dのライフゲームをネットで検索してみると、保存が効かないものが多く考察があまりできないことが多かったので頑張りました 改善したい箇所 ルールなどの考察が開発者自身も不十分 作成することに頭が行きがちだったので今後考察して改善していきたいです。 UI... 改善したいです。 おわりに ここまで読んでくださりありがとうございました! 実はこの製作物は友人とハッカソンのために面白そうだから作ったのですがあまり受けませんでした。。。(少し尖っていたかも) 本ゲームの不具合、改善点、技術的な疑問点などありましたらご気軽に質問ください! また、よろしければ遊んでみてください!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go ポインタとは~なぜ必要?

AWSのLambda関数を触っててGoのチュートリアルが読めなかったので、基礎的なところから勉強したことを記す。 ポインタの概念 ポインタ=実体(インスタンス)が格納されたメモリのアドレス package main import "fmt" func main() { var i int //int型の100という実体 i = 100 //int型のポインタ型変数pを定義 var p *int p = &i fmt.Println(i) //100 fmt.Println(p) //0xc00018c008 fmt.Println(*p) //*をつけることでリテラル(数値や文字列を直接に記述した定数のこと)を参照できる } ここで疑問が湧いた。 ポインタってなぜ必要なのか? それは、値渡しだけではなく参照渡しができるから。 値渡し package main import "fmt" func main() { var i int i = 100 fmt.Println(i) //100 hoge(i) //101 fmt.Println(i) //100 } func hoge(i int) { i += 1 fmt.Println(i) } 参照渡し package main import "fmt" func main() { var i int i = 100 fmt.Println(i) //100 hoge(&i) //101 fmt.Println(i) //101 } func hoge(i *int) { *i += 1 fmt.Println(*i) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】ログライブラリzapを使う時はglobal loggerが便利!

はじめに Goのログライブラリで人気なzap。 私も使っているのですが、インスタンスを引数で受け渡す必要があるのが少し面倒な気がします。 main.go package main import "go.uber.org/zap" func main() { logger, _ := zap.NewProduction() defer logger.Sync() sugar := logger.Sugar() // 引数で渡す hoge.Hoge(sugar) } hoge.go package hoge // ログ出力したい func Hoge(s *zap.SugaredLogger) { url := "http://example.com" s.Infof("error: %s", url) } 規模が小さい時はそこまで気になりませんでしたが、大きくなるにつれて徐々に気になるようになりました。 ネストされたところでログ出力したいがために、そこへ引数リレーしていくのがちょっと辛いです。 別の使い方がないかと思って調べてみると、global loggerを使うと解決できそうだったので、この記事で解説していきたいと思います。 解決策 2つありますが、私は前者推しです。 global loggerを使う main.go package main import "go.uber.org/zap" func main() { logger, _ := zap.NewProduction() defer logger.Sync() // こいつがキモ zap.ReplaceGlobals(logger) hoge.Hoge() } hoge.go package hoge import "go.uber.org/zap" // ログ出力したい func Hoge() { url := "http://example.com" zap.S().Infof("error: %s", url) } 引数渡しなしで、いい感じにログ出力を実装することができました! zap.ReplaceGlobalsとは 公式より引用 https://pkg.go.dev/go.uber.org/zap#example-ReplaceGlobals func ReplaceGlobals(logger *Logger) func() ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a function to restore the original values. It's safe for concurrent use. zapにはL()やS()といったglobal loggerを返す関数が用意されており、ReplaceGlobalsでglobal loggerを登録する形になります。 以下のzapのソースコード読んだ方が話早いかもです。 https://github.com/uber-go/zap/blob/master/global.go global.go抜粋 var ( _globalMu sync.RWMutex _globalL = NewNop() _globalS = _globalL.Sugar() ) // L returns the global Logger, which can be reconfigured with ReplaceGlobals. // It's safe for concurrent use. func L() *Logger { _globalMu.RLock() l := _globalL _globalMu.RUnlock() return l } // S returns the global SugaredLogger, which can be reconfigured with // ReplaceGlobals. It's safe for concurrent use. func S() *SugaredLogger { _globalMu.RLock() s := _globalS _globalMu.RUnlock() return s } // ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a // function to restore the original values. It's safe for concurrent use. func ReplaceGlobals(logger *Logger) func() { _globalMu.Lock() prev := _globalL _globalL = logger _globalS = logger.Sugar() _globalMu.Unlock() return func() { ReplaceGlobals(prev) } } パッケージスコープで変数宣言する logger.go // zapをwrapしたようなパッケージ package logger import "go.uber.org/zap" func initLogger() *zap.SugaredLogger { logger, _ := zap.NewProduction() defer logger.Sync() sugar := logger.Sugar() return sugar } var Sugar = initLogger() hoge.go package hoge imoprt logger // ログ出力したい func hoge() { url := "http://example.com" logger.Sugar.Infof("error: %s", url) } 上記のように、パッケージスコープにexportedな変数Sugarを宣言して、それをよそのパッケージでも使うという手法です。 ただ個人的には、変数Sugarがどこでも上書きできてしまうのであまり好みません。 const定義もできないですしね。 というかやっていること自体はReplaceGlobalsとほぼ一緒で、自前で用意するかパッケージで用意されているものを使うかの違いですね。 公式の推しは引数リレーっぽい この問題にぶち当たって色々調べている時に、以下のissueがとても参考になりました。 contributerの方が以下のように発言されていました。 Zap prefers not to provide implicit default global behavior, favoring explicit configuration in your main(). The default global logger used by zap.L() and zap.S() is a no-op logger. To configure the global loggers, you must use ReplaceGlobals. The approach we recommend is to not rely on global loggers at all. Instead, build a logger in your main() and pass it down to the components that need to perform logging operations explicitly. we believe that it's cleaner software design to not rely on any global state in our applications. We believe that the verbosity trade-off is worth it. The trade-off of Zap may not be worth it for simple systems. By "pass it down" I meant to instantiate the logger in your main(), not in init(), and then passing it explicitly as an argument to all components that need it, without ever using zap.ReplaceGlobals. ソフトウェア設計の観点から、loggerを必要とする関数に明示的な引数として渡してあげた方が良い、といった趣旨のコメントです。 まあわかるけどちょっと規模大きくなるとめんどうだな。。というのが私見です。 もちろんPJの状況に合わせて選定していくのが一番なので、一概にどちらが良い悪いはないと思います。 さいごに Twitterの方でも、モダンな技術習得やサービス開発の様子を発信したりしているので良かったらチェックしてみてください! Goの人気ログライブラリzapに関する記事書いた!⬇️【Go】ログライブラリzapを使う時はglobal loggerが便利!https://t.co/UGKbW9qZ7tglobal loggerの日本語情報があまりなかったので書いてみたzapの使い方って、READMEにはすごいシンプルにしか書いてないから参考になるかもしれない?— やぎぬ?QOL追求エンジニア (@yagi_eng) May 9, 2021 また、BOT開発を通じてGoとLINE BOTにまとめて入門する記事をZennに掲載していますので、良かったらそちらもご覧ください! ZennでGoとLINE BOTの記事を書いてみました⬇️BOT開発を通じてGoとLINE BOTにまとめて入門するhttps://t.co/QqsEESJMKa5ステップに分け、「Hello Worldから始めて、飲食店検索ができるLINE BOTの実装まで」を解説していますGoやLINE BOTに興味のある人は是非読んでみてください?24,000字超え?— やぎぬ?行動力エンジニア (@yagi_eng) November 7, 2020 参考 github.com/uber-go/zap zap - ReplaceGlobals
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mac VSCode dlvでGoのデバッグをする方法

goをVSCodeでデバッグするには、dlvというものが必要らしい。 dlvは、Goのデバッガのこと。静的型付け言語?のため、強者はlog.Printf("%+v")でも問題箇所に気づくことはできるらしいが、delveを使ったデバッグは便利とのこと。 dlvをインストールするのに若干ハマったので備忘録として残しておく。 環境 VS Code Mac Os brew goのインストール brew install go go version go version go1.16.3 darwin/amd64kkk GOPATHを通しておく。 $echo 'export PATH=~/go/bin:$PATH'>>~/.bash_profile dlvのインストール 試したこと brew install go-delve/delve/delve brew でdlvをインストールしようとしたら、↓で怒られた。 Error: homebrew-core is a shallow clone. To `brew update`, first run: git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow This command may take a few minutes to run due to the large size of the repository. This restriction has been made on GitHub's request because updating shallow clones is an extremely expensive operation due to the tree layout and traffic of Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you automatically to avoid repeatedly performing an expensive unshallow operation in CI systems (which should instead be fixed to not use shallow clones). Sorry for the inconvenience! ==> Tapping go-delve/delve Cloning into '/usr/local/Homebrew/Library/Taps/go-delve/homebrew-delve'... remote: Enumerating objects: 48, done. remote: Total 48 (delta 0), reused 0 (delta 0), pack-reused 48 Receiving objects: 100% (48/48), 12.44 KiB | 509.00 KiB/s, done. Resolving deltas: 100% (19/19), done. Tapped (29 files, 53.7KB). ==> Tapping homebrew/cask Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask'... remote: Enumerating objects: 570158, done. remote: Counting objects: 100% (509/509), done. remote: Compressing objects: 100% (322/322), done. remote: Total 570158 (delta 259), reused 415 (delta 187), pack-reused 569649 Receiving objects: 100% (570158/570158), 250.97 MiB | 9.20 MiB/s, done. Resolving deltas: 100% (402517/402517), done. Tapped 3899 casks (3,995 files, 269.2MB). ==> Searching for similarly named formulae... Error: No similarly named formulae found. Error: No available formula or cask with the name "go-delve/delve/delve". ==> Searching for a previously deleted formula (in the last month)... Error: No previously deleted formula found. formulaeがないとのこと。 formulaeとは、「調理法、手順」という意味で、Homebrewでは「ビルド方法・手順が書かれたスクリプト」のこと。 https://qiita.com/b4b4r07/items/6efebc2f3d1cbbd393fc#1-3 少し調べたが、あまり解決策っぽいのは出てこなかったので、 brewでインストールするのは諦めて、↓のようにすると無事にインストールできた。 go get -u github.com/go-delve/delve/cmd/dlv go getでは、コマンドラインツールの実行ファイルを勝手にインストールしてくれるっぽい。 ①go getが叩かれるとGoで書かれたコマンドラインツールの実行ファイルをGOPATH/bin配下に自動的に置いてくれます。 ②①と同じタイミングでGOPATH/srcにパッケージのソースコードが置かれます。ちなみに、go getでは取得したパッケージの依存パッケージ(importの中に書いてあるパッケージ)も一緒にダウンロードしてくれます。 https://qiita.com/yu19991013/items/ae4f6e0ebd59dfb9bc3d dlv version Delve Debugger Version: 1.6.0 Build: $Id: 8cc9751909843dd55a46e8ea2a561544f70db34d プロジェクトの作成 Goは$GOPATHにリポジトリとかgo getで取得してビルドされた実行ファイルが置かれる。 ~/goのフォルダの下にsrcを作ってそこにプロジェクトを作成するのがお作法らしい? ~/go ├── bin ├── pkg │   ├── mod │   └── sumdb └── src └── hello //helloというフォルダを作成してこの中で、.goファイルの作成 VSCodeでデバッグしようとすると、開かれたディレクトリのmain()から実行される。 最初は、複数ファイルにmain()を使用していて、うまくデバッグできなかった。 よって、一つのmain.goファイルの中で関数を分けるか、パッケージを作成してimportする。 パッケージの作成方法とimportに関しては、改めて勉強し記事にする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む