# Converting between Go and `cty` values While `cty` provides a representation of values within its own type system, a calling application will inevitably need to eventually pass values to a native Go API, using native Go types. [The `gocty` package](https://godoc.org/github.com/apparentlymart/go-cty/cty/gocty) aims to make conversions between `cty` values and Go values as convenient as possible, using an approach similar to that used by `encoding/json` where the `reflect` package is used to define the desired structure using Go native types. ## From Go to `cty` Converting Go values to `cty` values is the task of the `ToCtyValue` function. It takes an arbitrary Go value (as an `interface{}`) and `cty.Type` describing the shape of the desired value. The given type is used both as a conformance check and as a source of hints to resolve ambiguities in the mapping from Go types. For example, it is valid to convert a Go slice to both a `cty` set and list types, and so the given `cty` type is used to indicate which is desired. The errors generated by this function use terminology aimed at the developers of the calling application, since it's assumed that any problems encountered are bugs in the calling program and are thus "should never happen" cases. Since unknown values cannot be represented natively in Go's type system, `gocty` works only with known values. An error will be generated if a caller attempts to convert an unknown value into a Go value. ## From `cty` to Go Converting `cty` values to Go values is done via the `FromCtyValue` function. In this case, the function mutates a particular Go value in place rather than returning a new value, as is traditional from similar functions in packages like `encoding/json`. The function must be given a non-nil pointer to the value that should be populated. If the function succeeds without error then this target value has been populated with data from the given `cty` value. Any errors returned are written with the target audience being the hypothetical user that wrote whatever input was transformed into the given cty value, and thus the terminology used is `cty` type system terminology. As a concrete example, consider converting a value into a Go `int8`: ```go var val int8 err := gocty.FromCtyValue(value, &val) ``` There are a few different ways that this can fail: * If `value` is not a `cty.Number` value, the error message returned says "a number is required", assuming that this value came from user input and the user provided a value of the wrong type. * If `value` is not an integer, or it's an integer outside of the range of an `int8`, the error message says "must be a whole number between -128 and 127", again assuming that this was user input and that the target type here is an implied constraint on the value provided by the user. As a consequence, it is valid and encouraged to convert arbitrary user-supplied values into concrete Go data structures as a concise way to express certain data validation constraints in a declarative way, and then return any error message verbatim to the end-user. ## Converting to and from `struct`s As well as straightforward mappings of primitive and collection types, `gocty` can convert object and tuple values to and from values of Go `struct` types. For tuples, the target `struct` must have exactly the same number of fields as exist in the tuple, and the fields are used in the order they are defined with no regard to their names or tags. A `struct` used to decode a tuple must have all public attributes. These constraints mean that generally-speaking it will be hard to re-use existing application structs for this purpose, and instead a specialized struct must be used to represent each tuple type. For simple uses, a struct defined inline within a function can be used. For objects, the mapping is more flexible. Field tags are used to express which struct fields correspond to each object attribute, as in the following example: ```go type Example struct { Name string `cty:"name"` Age int `cty:"age"` } ``` For the mapping to be valid, there must be a one-to-one correspondence between object attributes and tagged struct fields. The presence or absense of attribute tags in the struct is used to define which attributes are valid, and so error messages will be generated for any extraneous or missing attributes. Additional fields may be present without tags, but all fields with tags must be public. ## Dynamically-typed Values If parts of the `cty` data structure have types that can't be known until runtime, it is possible to leave these portions un-decoded for later processing. To achieve this, `cty.DynamicPseudoType` is used in the type passed to the two conversion functions, and at the corresponding place in the Go data structure a `cty.Value` object is placed. When converting from `cty` to Go, the portion of the value corresponding to the dynamic pseudo-type is assigned directly to the `cty.Value` object with no conversion, so the calling program can then use the core `cty` API to interact with it. The converse is true for converting from Go to `cty`: any valid `cty.Value` object can be provided, and it will be included verbatim in the returned `cty.Value`. ```go type Thing struct { Name string `cty:"name"` ExtraData cty.Value `cty:"extra_data"` } thingType := cty.Object(map[string]cty.Type{ "name": cty.String, "extra_data": cty.DynamicPseudoType, }) thingVal := cty.ObjectVal(map[string]cty.Value{ "name": cty.StringVal("Ermintrude"), "extra_data": cty.NumberIntVal(12), }) var thing Thing err := gocty.FromCtyValue(thingVal, &thing) // (error check) fmt.Printf("extra_data is %s", thing.ExtraData.Type().FriendlyName()) // Prints: "extra_data is number" ``` ## Conversion of Capsule Types Since capsule types encapsulate native Go values, their handling in `gocty` is a simple wrapping and un-wrapping of the encapsulated value. The encapsulated type and the type of the target value must match. Since capsule values capture a pointer to the target value, it is possible to round-trip a pointer from a Go value into a capsule value and back to a Go value and recover the original pointer value, referring to the same in-memory object. ## Implied `cty` Type of a Go value In simple cases it can be desirable to just write a simple type in Go and use it immediately in conversions, without needing to separately write out a corresponding `cty.Type` expression. The `ImpliedType` function helps with this by trying to generate a reasonable `cty.Type` from a native Go value. Not all `cty` types can be represented in this way, but if the goal is a straightforward mapping to a convenient Go data structure then this function is suitable. The mapping is as follows: * Go's int, uint and float types all map to `cty.Number`. * Go's bool type maps to `cty.Bool` * Go's string type maps to `cty.String` * Go slice types map to `cty` lists with the element type mapped per these rules. * Go maps _with string keys_ map to `cty` maps with the element type mapped per these rules. * Go struct types are converted to `cty` object types using the struct tag convention described above and these mapping rules for each tagged field. * A Go value of type `cty.Value` maps to `cty.DynamicPseudoType`, allowing for values whose precise type isn't known statically. `ImpliedType` considers only the Go type of the provided value, so it's valid to pass a nil or zero value of the type. When passing `nil`, be sure to convert it to the target type, e.g. `[]int(nil)`.