ChatGPT - gpts: tool cheat sheet
launch.json
- 現在開いているコードをデバックする: Debug Current Go File
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Go Test",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"args": ["-test.run", "Test", "-test.v"],
"showLog": true,
"env": {},
"buildFlags": "-gcflags 'all=-N -l'",
"logOutput": "rpc" // Delveのログ出力を最小限に抑える
},
{
"name": "Debug Current Go File",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${file}",
"env": {},
// "args": ["${input:argument}"],
"console": "integratedTerminal",
// これがないと、ルートディレクトリで実行した時と、個別のファイルをデバックしたときの読み込みパスが同じにならない
"cwd": "${workspaceFolder}"
}
]
}
スライスは配列の要素を柔軟に操作するためのラッパーのようなものであり、動的なサイズ変更が可能なデータ構造です。 一方、配列は固定サイズでメモリ効率が良く、主に固定サイズのデータが必要な場面で使用されます。
// 既存の配列からスライスを作成
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // sは[2, 3, 4]となる
// make関数を使用してスライスを作成
s := make([]int, 5) // 長さ5のスライスを作成 [0, 0, 0, 0, 0]
// S[i:] はスライスのi番目から最後までを取得
s := []int{1, 2, 3, 4, 5}
subSlice := s[2:] // subSliceは[3, 4, 5]となる
// S[:i] はスライスの最初からi番目までを取得
subSlice := s[:3] // subSliceは[1, 2, 3]となる
// S[i:j] はスライスのi番目からj番目までを取得
subSlice := s[1:4] // subSliceは[2, 3, 4]となる
src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src) // dstは[1, 2, 3]となる
s := []int{1, 2, 3}
s = append(s, 4) // sは[1, 2, 3, 4]となる
// 複数要素を末尾追加
s = append(s, 5, 6) // sは[1, 2, 3, 4, 5, 6]となる
s := []int{2, 3, 4}
s = append([]int{1}, s...) // s は[1, 2, 3, 4]となる
s :make([]int, 0, 5) // 長さ0、容量5のスライスを作成
// []
s := make([]int, 3, 5) // 長さ3、容量5のスライスを作成
// [0, 0, 0]
// 長さの取得
length := len(s) // 3
// 容量の取得
capacity := cap(s) // 5
s := []int{1, 2, 3, 4, 5}
// 2番目の要素(値3)を削除
s = append(s[:2], s[3:]...) // sは[1, 2, 4, 5]となる
s := []int{1, 2, 3, 4, 5}
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
// sは[5, 4, 3, 2, 1]となる
s := []int{1, 2, 3}
s = append(s[:2], s[2:]...) // sは[1, 2, 3]と変わらない
s = append(s[:2], s[3:]...) // 2番目の要素を削除し、[1, 2]となる
s := []int{1, 2, 3, 4, 5}
target := 3
found := -1
for i, v := range s {
if v == target {
found = i
break
}
}
// foundは2(3が見つかったインデックス)となる。見つからなければ-1。
以下に、スライスの複製に関するチートシートを、コメントで結果が分かる形式でまとめました。
s1 := []int{1, 2, 3}
s2 := s1 // s2は[1, 2, 3]となる(s1の浅いコピー)
s2[0] = 10 // s1とs2はどちらも[10, 2, 3]となる
s1 := []int{1, 2, 3}
s2 := make([]int, len(s1))
copy(s2, s1) // s2は[1, 2, 3]となる(s1の深いコピー)
s2[0] = 10 // s1は[1, 2, 3]のままで、s2は[10, 2, 3]となる
s1 := []int{1, 2, 3}
s2 := make([]int, len(s1), cap(s1)+5)
copy(s2, s1) // s2は[1, 2, 3]となる(容量はs1より大きい)
s1 := [][]int{
{1, 2, 3},
{4, 5, 6},
}
s2 := make([][]int, len(s1))
for i := range s1 {
s2[i] = make([]int, len(s1[i]))
copy(s2[i], s1[i]) // s2の各スライスはs1の各スライスの深いコピーとなる
}
// s2は[[1, 2, 3], [4, 5, 6]]となる
s1 := []int{1, 2, 3, 4, 5}
s2 := make([]int, 2)
copy(s2, s1[1:3]) // s2は[2, 3]となる(s1の一部を深いコピー)
- 浅いコピー: スライスのポインタだけがコピーされ、元のデータは共有されるため、どちらかを変更するともう一方も変更されます。
- 深いコピー:
copy
関数を使用して、新しいスライスに元のデータを全てコピーします。これにより、元のスライスと新しいスライスは独立します。
- スライスのゼロ値:
nil
スライスは長さ 0 かつ容量 0 であり、要素を持たないが、append
可能です。 以下に、2 次元配列の基本操作に関するチートシートを作成しました。これを先ほどの「Slice」と同じ階層に配置してください。
2 次元配列は、配列の配列です。各要素はさらに配列となっており、行列のような構造を持ちます。Go では、2 次元配列のサイズは固定されており、スライスとは異なり動的なサイズ変更はできません。
// サイズが決まっている2次元配列を作成
var arr [3][4]int // 3x4の2次元配列を作成(すべての要素は0)
// 初期値を設定して2次元配列を作成
arr := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
// 要素の取得と更新
arr := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
value := arr[1][2] // 6を取得
arr[0][1] = 10 // arr[0][1]に10を設定
arr := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
// すべての要素にアクセスするための二重ループ
for i := 0; i < len(arr); i++ {
for j := 0; j < len(arr[i]); j++ {
fmt.Println(arr[i][j])
}
}
// rangeを使ったループ
for i, row := range arr {
for j, val := range row {
fmt.Printf("arr[%d][%d] = %d\n", i, j, val)
}
}
arr := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
rows := len(arr) // 行の数(2)
cols := len(arr[0]) // 列の数(3)
// 配列は固定サイズであるため、完全にコピーするには手動でループする必要があります
src := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
var dst [2][3]int
for i := range src {
for j := range src[i] {
dst[i][j] = src[i][j]
}
}
以下に、Golang で 2 次元スライスに値を追加するためのチートシートを作成しました。コメントで簡単な説明を加えています。
2 次元スライスは、スライスのスライスとして実装されます。各スライスは異なる長さを持つことができ、動的に要素を追加することが可能です。
// 空の2次元スライスを作成
matrix := [][]int{}
// 直接値を設定して作成
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
append
はスライスの末尾に要素を追加し、容量が足りない場合は新しい配列を確保して返します。そのため、結果を元のスライスに再代入する必要があります。
// 新しい行を追加
newRow := []int{10, 11, 12}
matrix = append(matrix, newRow)
// matrixは[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]となる
// 1行目(インデックス0)に新しい要素を追加
matrix[0] = append(matrix[0], 4)
// matrixは[[1, 2, 3, 4], [4, 5, 6], [7, 8, 9]]となる
// 1行目(インデックス0)の2番目の位置(インデックス1)に値を挿入
index := 1
matrix[0] = append(matrix[0][:index+1], matrix[0][index:]...)
matrix[0][index] = 99
// matrixは[[1, 99, 2, 3, 4], [4, 5, 6], [7, 8, 9]]となる
// 2行目(インデックス1)を削除
matrix = append(matrix[:1], matrix[2:]...)
// matrixは[[1, 99, 2, 3, 4], [7, 8, 9]]となる
// 1行目(インデックス0)の3番目の要素(インデックス2)を削除
matrix[0] = append(matrix[0][:2], matrix[0][3:]...)
// matrixは[[1, 99, 3, 4], [7, 8, 9]]となる
- スライスは可変長であり、
append
を使って動的に要素を追加できます。 - 2 次元スライスはスライスのスライスであり、各行が異なる長さを持つことが可能です。
- 挿入や削除の操作では、新しいスライスを作成して既存のスライスを再構築することが多いです。
2 次元スライスは、スライスのスライスとして実装されます。各スライスは異なる長さを持つことができ、動的に要素を追加することが可能です。
// 空の2次元スライスを作成
matrix := [][]int{}
// 直接値を設定して作成
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
// 新しい行を追加
newRow := []int{10, 11, 12}
matrix = append(matrix, newRow)
// matrixは[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]となる
// 1行目(インデックス0)に新しい要素を追加
matrix[0] = append(matrix[0], 4)
// matrixは[[1, 2, 3, 4], [4, 5, 6], [7, 8, 9]]となる
matrix := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
// 挿入したい位置のインデックス
index := 1
// 挿入する値
newValue := 99
// 挿入位置の前の部分をコピー
before := matrix[0][:index] // beforeは[1]
// 挿入位置の後の部分をコピー
after := matrix[0][index:] // afterは[2, 3]
// 新しいスライスを作成し、前の部分、新しい値、後の部分を結合
newRow := append(before, newValue) // newRowは[1, 99]
newRow = append(newRow, after...) // newRowは[1, 99, 2, 3]
// 元のスライスに新しい行を設定
matrix[0] = newRow
// 結果: matrixは[[1, 99, 2, 3], [4, 5, 6], [7, 8, 9]]となる
👆 同じ 👇
// 1行目(インデックス0)の2番目の位置(インデックス1)に値を挿入
index := 1
matrix[0] = append(matrix[0][:index+1], matrix[0][index:]...)
matrix[0][index] = 99
// matrixは[[1, 99, 2, 3, 4], [4, 5, 6], [7, 8, 9]]となる
// 2行目(インデックス1)を削除
matrix = append(matrix[:1], matrix[2:]...)
// matrixは[[1, 99, 2, 3, 4], [7, 8, 9]]となる
// 1行目(インデックス0)の3番目の要素(インデックス2)を削除
matrix[0] = append(matrix[0][:2], matrix[0][3:]...)
// matrixは[[1, 99, 3, 4], [7, 8, 9]]となる
- スライスは可変長であり、
append
を使って動的に要素を追加できます。 - 2 次元スライスはスライスのスライスであり、各行が異なる長さを持つことが可能です。
- 挿入や削除の操作では、新しいスライスを作成して既存のスライスを再構築することが多いです。
このチートシートを参考にして、Golang の 2 次元スライスの操作を習得してください。
//----------------------------------------
// Map declaration and initialization
//----------------------------------------
// マップを宣言(初期化なし)
var m map[string]int
// マップを初期化
m = make(map[string]int)
// 宣言と初期化を同時に行う
m := make(map[string]int)
// リテラルで初期化
m := map[string]int{
"apple": 120,
"banana": 150,
}
//----------------------------------------
// Set and get values in a map
//----------------------------------------
// 値を設定
m["apple"] = 130
// 値を取得
price := m["apple"]
fmt.Println("Apple price:", price) // 出力: Apple price: 130
//----------------------------------------
// Check if a key exists in the map
//----------------------------------------
// キーの存在確認
price, exists := m["banana"]
if exists {
fmt.Println("Banana price:", price)
} else {
fmt.Println("Banana is not found")
}
//----------------------------------------
// Delete a key-value pair from the map
//----------------------------------------
// 値の削除
delete(m, "apple")
//----------------------------------------
// Get the number of key-value pairs in the map
//----------------------------------------
length := len(m)
fmt.Println("Number of items in the map:", length)
//----------------------------------------
// Iterate over a map
//----------------------------------------
for fruit, price := range m {
fmt.Printf("%s costs %d yen\n", fruit, price)
}
//----------------------------------------
// Map keys must be unique
//----------------------------------------
// キーが重複すると、値が上書きされる
m["banana"] = 150
m["banana"] = 180 // 既存の"banana"の値が上書きされる
fmt.Println("Updated Banana price:", m["banana"]) // 出力: Updated Banana price: 180
//----------------------------------------
// Nested maps
//----------------------------------------
productPrices := map[string]map[string]int{
"fruits": {
"apple": 100,
"banana": 200,
},
"vegetables": {
"carrot": 80,
"onion": 50,
},
}
// ネストされたマップの値の取得
applePrice := productPrices["fruits"]["apple"]
fmt.Println("Apple price from nested map:", applePrice) // 出力: Apple price from nested map: 100
//----------------------------------------
// Shallow copy of a map
//----------------------------------------
newMap := make(map[string]int)
for k, v := range m {
newMap[k] = v
}
// newMapはmのコピーだが、完全なディープコピーではない
//----------------------------------------
// Using maps with structs
//----------------------------------------
type Product struct {
Name string
Price int
}
products := make(map[string]Product)
products["apple"] = Product{Name: "Apple", Price: 120}
// 構造体を使ったマップの値の取得
apple := products["apple"]
fmt.Println("Product:", apple.Name, "Price:", apple.Price) // 出力: Product: Apple Price: 120
//----------------------------------------
// Working with maps in JSON
//----------------------------------------
import (
"encoding/json"
"fmt"
)
// マップをJSONエンコード
jsonData, err := json.Marshal(m)
if err != nil {
fmt.Println(err)
}
fmt.Println("JSON data:", string(jsonData)) // 出力: {"banana":180}
// JSONからマップをデコード
jsonStr := `{"apple":130,"banana":150}`
var decodedMap map[string]int
err = json.Unmarshal([]byte(jsonStr), &decodedMap)
if err != nil {
fmt.Println(err)
}
fmt.Println("Decoded map:", decodedMap) // 出力: map[apple:130 banana:150]
- マップのキーは一意でなければならない。同じキーを再度追加すると、そのキーの値が上書きされます。
- マップは順序を保証しない。イテレーションの順序はランダムです。
- マップのゼロ値は
nil
。nil
マップに対して要素を追加しようとするとパニックが発生しますので、必ず初期化する必要があります。
slice := []int{5, 2, 6, 3, 1, 4}
// 昇順ソート
sort.Slice(slice, func(i, j int) bool {
return slice[i] < slice[j]
})
fmt.Println(slice) // [1 2 3 4 5 6]
// 降順ソート
sort.Slice(slice, func(i, j int) bool {
return slice[i] > slice[j]
})
fmt.Println(slice) // [6 5 4 3 2 1]
シンプルに昇順ソートするには、sort.Ints
、sort.Strings
、sort.Float64s
を使う。
//----------------------------------------
// Sort slice
//----------------------------------------
nums := []int{42, -10, 0, 8}
sort.Ints(nums)
fmt.Println(nums) // [-10 0 8 42]
strs := []string{"banana", "apple", "cherry"}
sort.Strings(strs)
fmt.Println(strs) // ["apple", "banana", "cherry"]
floats := []float64{3.14, 1.59, 2.65}
sort.Float64s(floats)
fmt.Println(floats) // [1.59, 2.65, 3.14]
sort.Reverse(slice)
nums := []int{42, -10, 0, 8}
// IntSliceを使ってソート
sort.Sort(sort.IntSlice(nums)) // 昇順にソートされる
fmt.Println(nums) // [-10 0 8 42]
// 逆順にソート
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
fmt.Println(nums) // [42 8 0 -10]
sort.Slice
//----------------------------------------
// Reverse string
//----------------------------------------
func reverseString(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
str := "hello"
reversed := reverseString(str)
fmt.Println(reversed) // "olleh"
func getRootDir() (string, error) {
currentDir, err := os.Getwd()
if err != nil {
return "", err
}
for {
if _, err := os.Stat(filepath.Join(currentDir, "go.mod")); err == nil {
return currentDir, nil
}
parentDir := filepath.Dir(currentDir)
if parentDir == currentDir {
return "", fmt.Errorf("go.mod not found")
}
currentDir = parentDir
}
}
Usage:
targetFile := filepath.Join(getRootDir(), "file.txt")