Go Commentary #15: Using Go embed, and Reflect

Using Go Embed

  • The go:embed directive tells the Go compiler to include files and folders into the compiled binary at build time. This means your application can access these resources directly from memory without needing to read from the disk at runtime.

  • Usage:

    • with a single file message.txt ("hello from bytesizego!")
    package main
    
    import (
      _ "embed"
      "fmt"
    )
    
    //go:embed message.txt
    var message string
    
    func main() {
      fmt.Println(message) // hello from bytesizego!
    }
    
    
    • with multiple files
    package main
    
    import (
      _ "embed"
      "fmt"
    )
    
    //go:embed messages/*.txt
    var messages embed.FS
    
    func main() {
      files, _ := messages.ReadDir("messages")
      for _, file := range files {
        data, _ := messages.ReadFile("messages/" + file.Name())
        fmt.Printf("File: %s\nContent: %s\n\n", file.Name(), data)
      }
    }
    
    • with a directory (the path specified in ReadFile is relative to the embedded root.)
    package main
    
    import (
      "embed"
      "fmt"
    )
    
    //go:embed static
    var staticFiles embed.FS
    
    func main() {
      data, _ := staticFiles.ReadFile("static/index.html")
      fmt.Println(string(data))
    }
    
  • Limitations:

    • File Size: Embedding large files can significantly increase your binary size.
    • File Changes: Changes to the embedded files require recompilation.

Reflecting on Go Reflection

  • Context: using generative AI tooling, generated code using Reflect package
bsVal := reflect.ValueOf(blockStore).Elem()

tables := bsVal.FieldByName("tables")

typ := tables.Type()
fmt.Printf("tables.Type: %v\n", typ)
for i := 0; i < typ.NumField(); i++ {
  fmt.Printf("tables %d: %s\n", i, typ.Field(i).Name)
}
for i := 0; i < typ.NumMethod(); i++ {
  fmt.Printf("method %d: %s\n", i, typ.Method(i).Name)
}
  • Laws of Reflection

    • Reflection goes from interface value to reflection object

    • Reflection goes from reflection object to interface value

    • To modify a reflection object, the value must be settable

    => In short, the Interface method is the inverse of the ValueOf function, except that its result is always of static type interface{}. Reiterating: Reflection goes from interface values to reflection objects and back again.

  • Zeroth Law: Use reflect at your own peril. Misuse it, and it will panic with no regrets.


https://www.bytesizego.com/blog/go-embed

https://www.dolthub.com/blog/2024-10-04-reflecting-on-reflect/

Subscribe to Dwarves Memo

Receive the latest updates directly to your inbox.