interface{}var w io.Writer = os.Stdout
f := w.(*os.File) // success
c := w.(*bytes.Buffer) // failure since the interface holds a *os.File not a *bytes.Buffer
c, ok := w.(*bytes.Buffer)
fmt and jsonfunc Println(args ...interface{}) {
// ...
for _, arg := range args {
switch a := arg.(type) {
case string: // concrete type
// do something with the string
case Stringer: // interface
// call the String() method on the interface to get the string representation
}
}
}
a takes on a value of the type it is, and when the case matches, a will have that corresponding type, meaning we can do things like call the methods on that Stringer interface==reflect.DeepEqual to do a reflection based equals that will look into slices and other normally non-comparable structures to check for equalitywant := struct{
someSlice := []int{1,2,3}
}
got := someFunction()
if !reflect.DeepEqual(got, want) {
fmt.Println("failed equality check")
}
{
"item": "album",
"album": {"title": "Quality Over Opinion"}
}
{
"item": "song",
"song": {"title": "Shallow Laughter", "artist": "Louis Cole"}
}
type Response struct {
Item string
Album string
Title string
Artist string
}
map[string]any then have logic for extracting the fields conditionally as requiredtype Person struct {
Name string `json:"name"`
}
func (p *Person) UnmarshalJSON(data []byte) error {
// uh oh stinky, this will recursively unmarshal
return json.Unmarshal(data, p)
}
func (p *Person) UnmarshalJSON(data []byte) error {
type wrapper Person
// we make a new variable aux which is a wrapper type. The pointer points to the same underlying memory
// of p, however in the type system the UnmarshalJSON method isn't defined for the wrapper type
// and so we can call json.Unmarshal without issues. Then we can do any custom validation we want to
aux := (*wrapper)(p)
if err := json.Unmarshal(data, aux); err != nil {
return err
}
// custom validation / logic
if p.Name == "" {
return errors.New("missing name")
}
return nil
}