Golangでディレクトリ内が空かどうかを判定する

最終的にはこれ func IsEmpty(name string) (bool, error) { f, err := os.Open(name) if err != nil { return false, err } defer f.Close() _, err = f.Readdirnames(1) // Or f.Readdir(1) if err == io.EOF { return true, nil } return false, err // Either not empty or error, suits both cases } つまり システムにはディレクトリが空かどうかの情報は無いからディレクトリの子があるかどうかで判断するしか無い File.Readdirnames() が最速 以下日本語要約 ディレクトリが空であるか否かは、その名前、作成時間、またはそのサイズ(ファイルの場合)のようなファイルシステムレベルのプロパティとして保存されていません。 つまり、os.FileInfoからこの情報を直接取得することはできません。最も簡単な方法は、ディレクトリの子(内容)をクエリすることです。 ioutil.ReadDir()はあまり良い選択ではありません。なぜなら、これはまず指定されたディレクトリのすべての内容を読み取り、それらを名前でソートし、その後スライスを返すからです。最も速い方法はDave Cが言及したように、File.Readdir()または(好ましくは)File.Readdirnames()を使用してディレクトリの子をクエリすることです。 File.Readdir()とFile.Readdirnames()の両方は、返される値の数を制限するために使用されるパラメータを取ります。1つの子をクエリするだけで十分です。Readdirnames()は名前のみを返すので、FileInfo構造体を取得(および構築)するためのさらなる呼び出しが必要ないため、速度が速くなります。 ディレクトリが空の場合、io.EOFがエラーとして返され(空のスライスやnilのスライスではない)ため、返された名前のスライスは必要ありません。 ...

2023-04-21 ·  2023-05-14 · 2 分 · 259 文字

Go では 複雑でコストのかかる処理を構文で隠してはいけないという基本的なルールがあります。

Go では複雑でコストのかかる処理を隠すような機能は実装されない []string を []interface{} に自動変換する良い方法や提供されている機能は無い func foo([]interface{}) { /* do somthing */ } func main() { var a[]string = []string{"hello", "world"} for(a) } 毎回以下のように実装する必要がある b = make([]interface{}, len(a), len(a)) for i := range a { b[i] = a[i] } 参考 go - Type converting slices of interfaces - Stack Overflow In Go, there is a general rule that syntax should not hide complex/costly operations. Converting a string to an interface{} is done in O(1) time. Converting a []string to an interface{} is also done in O(1) time since a slice is still one value. However, converting a []string to an []interface{} is O(n) time because each element of the slice must be converted to an interface{}. The one exception to this rule is converting strings. When converting a string to and from a []byte or a []rune, Go does O(n) work even though conversions are “syntax”. There is no standard library function that will do this conversion for you. Your best option though is just to use the lines of code you gave in your question: ...

2022-07-15 ·  2022-07-15 · 2 分 · 266 文字

Golang 組み込み構造体へのキャスト方法(Goのポリモーフィズムの実現)

Golang 組み込み構造体へのキャスト方法(Goのポリモーフィズムの実現) Golangで組み込み構造体(親)へのキャストを行いたい場合は(ポリモーフィズムを得るためには)、インターフェイスの実装が必要 子から親への参照はある インターフェースの名前はGolangでは er が慣例 package main import "fmt" type Parent struct { Attr1 string } type Parenter interface { GetParent() Parent } type Child struct { Parent //embed Attr string } func (c Child) GetParent() Parent { return c.Parent } func setf(p Parenter) { fmt.Println(p) } func main() { var ch Child ch.Attr = "1" ch.Attr1 = "2" setf(ch) } // result {{2} 1} 参考 go - Golang interface cast to embedded struct - Stack Overflow あなたは、継承を使ったオブジェクト指向のデザインパターンを使おうとしています。これはGoでのやり方ではありません。また、Javaや同等のオブジェクト指向言語では、インターフェース名は’able’で終わります。Goでは、インターフェイス名は’er’で終わるのが慣例です。 You are trying to use an object oriented design pattern with inheritance. This is not how to do this in Go. Beside, interface names end in ‘able’ in Java or equivalent object oriented languages. In Go the convention is to end interface names with ’er’. ...

2022-07-11 ·  2022-07-11 · 1 分 · 210 文字

go generate assests box

go generate を使った assets ディレクトリの静的組み込みバイナリ処理 モノリポで管理しているSPAなクライアント側の成果物 (dist) を gin で静的配布 できないかと思った際に調べた内容。 結局使用していないが、バイナリ化する手順としては使えそうなのでメモしておく。 ディレクトリは以下の様な形 ├── Makefile ├── assets -> ../../client/back/dist ├── box │ ├── blob.go │ └── box.go └─generator.go Makefile まずは関係ないけど、Makefileって@書けば && バックスラッシュ連結とかいらんのかという発見 ./... 指定で全てを対象に指定 generate: @go generate ./... @echo "[OK] Files added to embed box!" generator.go 1行目はfmtをかけると自動付与された // +build ignore コメントにより通常ビルド対象から外れる設定 生成される go ファイルは blob.go で box 配下に出力される f, err := os.Create(blobFileName) や、 embedFolder string = "../assets/" から current directory は box 配下の模様 //go:build ignore // +build ignore package main import ( "bytes" "fmt" "go/format" "io/ioutil" "log" "os" "path/filepath" "strings" "text/template" ) const ( blobFileName string = "blob.go" embedFolder string = "../assets/" ) // Define vars for build template var conv = map[string]interface{}{"conv": fmtByteSlice} var tmpl = template.Must(template.New("").Funcs(conv).Parse(`package box // Code generated by go generate; DO NOT EDIT. func init() { {{- range $name, $file := . }} box.Add("{{ $name }}", []byte{ {{ conv $file }} }) {{- end }} }`), ) func fmtByteSlice(s []byte) string { builder := strings.Builder{} for _, v := range s { builder.WriteString(fmt.Sprintf("%d,", int(v))) } return builder.String() } func main() { // Checking directory with files if _, err := os.Stat(embedFolder); os.IsNotExist(err) { log.Fatal("Configs directory does not exists!") } // Create map for filenames configs := make(map[string][]byte) // Walking through embed directory err := filepath.Walk(embedFolder, func(path string, info os.FileInfo, err error) error { relativePath := filepath.ToSlash(strings.TrimPrefix(path, embedFolder)) if info.IsDir() { // Skip directories log.Println(path, "is a directory, skipping...") return nil } else { // If element is a simple file, embed log.Println(path, "is a file, packing in...") b, err := ioutil.ReadFile(path) if err != nil { // If file not reading log.Printf("Error reading %s: %s", path, err) return err } // Add file name to map configs[relativePath] = b } return nil }) if err != nil { log.Fatal("Error walking through embed directory:", err) } // Create blob file f, err := os.Create(blobFileName) if err != nil { log.Fatal("Error creating blob file:", err) } defer f.Close() // Create buffer builder := &bytes.Buffer{} // Execute template if err = tmpl.Execute(builder, configs); err != nil { log.Fatal("Error executing template", err) } // Formatting generated code data, err := format.Source(builder.Bytes()) if err != nil { log.Fatal("Error formatting generated code", err) } // Writing blob file if err = ioutil.WriteFile(blobFileName, data, os.ModePerm); err != nil { log.Fatal("Error writing blob file", err) } } box.go //go:generate go run ../generator.go で go generate 時に実行される処理を記載する プロジェクトルートから ./... で全ファイルが対象として起動されたあと、box.go を見つけて、 先頭に//go:generate... があるからその後ろに定義しているコマンドを実行するような動き //go:generate go run ../generator.go package box type embedBox struct { storage map[string][]byte } // Create new box for embed files func newEmbedBox() *embedBox { return &embedBox{storage: make(map[string][]byte)} } // Add a file to box func (e *embedBox) Add(file string, content []byte) { e.storage[file] = content } // Get file's content func (e *embedBox) Get(file string) []byte { if f, ok := e.storage[file]; ok { return f } return nil } // Embed box expose var box = newEmbedBox() // Add a file content to box func Add(file string, content []byte) { box.Add(file, content) } // Get a file from box func Get(file string) []byte { return box.Get(file) } blob.go go generate 後の成果物 generator.go の template 処理で書いている通り、box.Add でバイナリデータをキー(相対パス)に紐付けるコードが生成されている package box // Code generated by go generate; DO NOT EDIT. func init() { box.Add("js/app.js", []byte{0, 0, ... : blob.goの使用方法 fmt.Println(string(box.Get("js/app.js"))) 参考 The easiest way to embed static files into a binary file in your Golang app (no external dependencies) - DEV Community ...

2022-06-22 ·  2023-04-26 · 3 分 · 559 文字

aws vault invalid client token id error

aws-vault で InvalidClientTokenId: The security token included in the request is invalid で怒られる │ Error: error reading IAM Role (rds-enhanced-monitoring-dev-db): InvalidClientTokenId: The security token included in the request is invalid │ status code: 403, request id: d09fe380-0c00-4485-9aeb-1e58740fdcb3 ここに答えがあった Error: The security token included in the request is invalid · Issue #260 · 99designs/aws-vault · GitHub I’ve encountered the same problem. It’s caused by the AWS API restrictions, that won’t allow you to touch IAM related APIs using the account with MFA enabled, unless you pass the MFA token within the request. Work around it is to call: $ aws-vault exec admin-iam –no-session – your_command It won’t use temporary credentials then. I know that’s not a perfect solution, but it works ;) ...

2021-12-02 ·  2023-09-22 · 1 分 · 125 文字