Closed manterfield closed 1 year ago
package main
import (
"fmt"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/json"
)
func convertToInterface(val cty.Value) interface{} {
switch val.Type() {
case cty.String:
return val.AsString()
case cty.Bool:
return val.True()
case cty.Number:
return val.AsBigFloat().String()
case cty.Object:
obj := make(map[string]interface{})
val.ForEach(func(key cty.Value, value cty.Value) bool {
obj[key.AsString()] = convertToInterface(value)
return true
})
return obj
case cty.List:
list := make([]interface{}, 0)
val.ForEachElement(func(index int, value cty.Value) bool {
list = append(list, convertToInterface(value))
return true
})
return list
default:
return nil
}
}
func main() {
hcl := `{
"foo": "foostring",
"bar": true,
"buzz": [1, 2, 3]
}`
val, err := json.Unmarshal([]byte(hcl), cty.DynamicPseudoType)
if err != nil {
fmt.Println(err)
return
}
result := convertToInterface(val)
fmt.Printf("%+v\n", result)
}
@ljluestc Lovely example, thank you. This is the recursive version I had in mind, it's fairly neat so probably not a big deal that it's not built in.
I'm probably just missing something obvious here, and if so apologies for the noise.
I'm attempting to take user input from HCL that is composed of data with types that are unknown until runtime. The example HCL could look something like this:
My first attempt was to decode this into cty Values and then transform using
gocty.FromCtyValue(val, &decodedVal)
where decoded val ismap[string]interface{}
. Of course, that doesn't work asFromCtyValue
uses reflection on the type and maps to specific concrete types.interface{}
doesn't match, so I geterror: "incorrect type"
which is the default error case.I can see I could put something together using recursion myself, and if all else fails that's what I'll do. The only thing that has stopped me is the assumption that I must be missing a built in way to handle this case. Especially since the package docs have quite a bit of material on converting between unknown types etc.