How to check reflect.Value is nil or not? - go

I have this code:
package main
import (
"fmt"
"reflect"
)
type cmd struct{
Echo func(string) (string,error)
}
func main() {
cmd := cmd{
Echo : func(arg string) (string, error) {
return arg, nil
},
}
result := reflect.ValueOf(cmd).FieldByName("Echo").Call([]reflect.Value{reflect.ValueOf("test")})
if result[1] == nil{
fmt.Println("ok")
}
}
I want to check if my error is nil, but in my code, it doesn't work cuz it has different types. I try to make like this :
reflect[1] == reflect.Value(reflect.ValueOf(nil))
So it has the same type but the value of reflect.Value(reflect.ValueOf(nil)) isn't nil, it is <invalid reflect.Value>.

Use .IsNil() to check whether the value that's stored in reflect.Value is nil.
if result[1].IsNil() {
fmt.Println("ok")
}
Or you can use .Interface() to get the actual value that's stored in reflect.Value and check whether this is nil.
if result[1].Interface() == nil {
fmt.Println("ok")
}

Related

How to change empty *strings to nil using mold package?

During validation of user input I wanna set to nil some empty *strings in some structs.
E.g. I have this struct:
type User {
Username *string
}
If Username == "" I wanna set Username to nil before proceed.
But I wanna do this using tags, e.g.:
type User {
Username *string `mod:"nil_if_empty"`
}
because I'm already using this package: https://github.com/go-playground/mold in my project for sanitize.
So I'm creating a custom function to set empty strings to nil, but I'm stuck.
Reproduction: https://play.golang.org/p/_DlluqE2Y3k
package main
import (
"context"
"fmt"
"log"
"reflect"
"github.com/go-playground/mold/v3"
)
var tform *mold.Transformer
func main() {
tform = mold.New()
tform.Register("nilEmptyString", nilEmptyString)
type Test struct {
String *string `mold:"nilEmptyString"`
}
myEmptyString := ""
tt := Test{String: &myEmptyString}
err := tform.Struct(context.Background(), &tt)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", tt)
}
func nilEmptyString(_ context.Context, _ *mold.Transformer, v reflect.Value, _ string) error {
s, ok := v.Interface().(*string)
if !ok { // ok is always false, why?
return nil
}
if s != nil && *s != "" {
return nil
}
if s != nil && *s == "" {
// v.SetPointer(nil) // should I use this?
}
// v.Set(nil) // how to do this?
return nil
}
Why ok in s, ok := v.Interface().(*string) is always false?
How to set v to nil? Why is v.Set(nil) wrong?
I hope this is a good question to ask on StackOverflow. If not tell me how to improve.
Thanks.

How to omit empty json fields using json.decoder

I try to understand why both functions return the same output.
As far as I understood, the point of omit empty is to not add that key to the result struct.
I wrote this example, I was expecting the first output not to have the "Empty" key, but for some reason its value still shows as 0.
package main
import (
"encoding/json"
"fmt"
"strings"
)
type agentOmitEmpty struct {
Alias string `json:"Alias,omitempty"`
Skilled bool `json:"Skilled,omitempty"`
FinID int32 `json:"FinId,omitempty"`
Empty int `json:"Empty,omitempty"`
}
type agent struct {
Alias string `json:"Alias"`
Skilled bool `json:"Skilled"`
FinID int32 `json:"FinId"`
Empty int `json:"Empty"`
}
func main() {
jsonString := `{
"Alias":"Robert",
"Skilled":true,
"FinId":12345
}`
fmt.Printf("output with omit emtpy: %v\n", withEmpty(strings.NewReader(jsonString)))
// output with omit emtpy: {Robert true 12345 0}
fmt.Printf("output regular: %v\n", withoutEmpty(strings.NewReader(jsonString)))
// output without omit: {Robert true 12345 0}
}
func withEmpty(r *strings.Reader) agentOmitEmpty {
dec := json.NewDecoder(r)
body := agentOmitEmpty{}
err := dec.Decode(&body)
if err != nil {
panic(err)
}
return body
}
func withoutEmpty(r *strings.Reader) agent {
dec := json.NewDecoder(r)
body := agent{}
err := dec.Decode(&body)
if err != nil {
panic(err)
}
return body
}
You need to define Empty as *int so it will be replaced with nil when there is no value. Then it will not be saved in the database.

Can a variable be used as a placeholder for a function call?

I am writing a program which has several structs and functions to handle these structs differently. I am having a generic function which calls the required function based on the inputs. Is there a generic way to use the returned value from getStruct()?
package main
var X func(s []string) A
var Y func(s []string) B
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
func newA(s []string) A {
a := A{
Name: s[0],
Place: s[1],
}
return a
}
func newB(s []string) B {
a := B{
Name: s[0],
Place: s[1],
Value: s[2],
}
return a
}
func getStruct(t string) interface{} {
switch {
case t == "A":
return X
case t == "B":
return Y
default:
return //someStruct
}
}
func main() {
buildNewStruct := getStruct("A") //Lets assume "A" here is got as an argument
var strSlice = []string{"Bob", "US"}
buildNewStruct(strSlice) //How to do this operation?
//I am hoping to use buildNewStruct(strSlice) to dynamically call
//either of newA(strSlice) or newB(strSlice) function
}
I have tried looking at this and this the later is not exactly the same as my question.
Since I am new to go, I am not sure if something like this is possible.
you can use the reflect package to set the struct properties to the equivalent index positioned value from an []interface{} slice.
package main
import (
"fmt"
"log"
"reflect"
)
func main() {
var a A
err := decode(&a, []interface{}{"Name", "Place"})
log.Println(err)
log.Println(a)
}
func decode(dst interface{}, values []interface{}) error {
rvptr := reflect.ValueOf(dst)
if rvptr.Kind() != reflect.Ptr {
return fmt.Errorf("value must be ptr")
}
rv := rvptr.Elem()
if rv.NumField() < len(values) {
return fmt.Errorf("too many values")
}
if rv.NumField() > len(values) {
return fmt.Errorf("too few values")
}
rvalues := reflect.ValueOf(values)
for i := range values {
f := rv.FieldByIndex([]int{i})
f.Set(rvalues.Index(i).Elem())
}
return nil
}
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
prints
$ go run main.go
2019/11/21 17:00:17 <nil>
2019/11/21 17:00:17 {Name Place}
The problem is the return type for the function.
func newA(in []string) interface{} {...}
func newB(in []string) interface{} {...}
func getStruct(name string) func([]string) interface{} {
switch name {
case "A": return newA
case "B": return newB
}
return nil
}
func main() {
buildNewStruct := getStruct("A")
var strSlice = []string{"Bob", "US"}
str:=buildNewStruct(strSlice)
if a, ok:=str.(A); ok {
...
}
}
With this approach, even though you saved some code by calling a unified buildNewStruct(), you have to use type assertions to figure out what is returned from that function, so this may not make a lot of sense. It depends on your exact use case though.

Go YAML parsing: mandatory fields

Summary:
I need to parse data in YAML format into golang struct. It there a way (library, attributes) to make some of the fields mandatory, i.e. to make Unmarshal function return the error in case if some field doesn't exist?
Example what is wanted:
Unmarshal function in this code should raise an error because input data doesn't contain 'b' field.
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type TestStruct struct {
FieldA string `yaml:"a"`
FieldB string `yaml:"b"`
}
func main() {
input := []byte(`{a: 1}`)
var output TestStruct
_ = yaml.Unmarshal(input, &output)
}
You can use this library's HasZero method to check wether there are any missing values in a struct. This will return true or false depending wether the struct is completely filled or not. Please see the playground example to get an idea.
But if you specifically need to tell what field is missing, you need to check wether the value is nil like in the example below.
package main
import (
"fmt"
"errors"
"gopkg.in/yaml.v2"
)
type TestStruct struct {
FieldA string `yaml:"a"`
FieldB string `yaml:"b"`
}
func main() {
input := []byte(`{a: 1}`)
var output TestStruct
if err := output.ParseFromFile(input); err != nil {
fmt.Println(err)
}
fmt.Println(output)
}
func (output *TestStruct) ParseFromFile(data []byte) error {
if err := yaml.Unmarshal(data, output); err != nil {
return err
}
if output.FieldA == "" {
return errors.New("Blank Field A")
}
if output.FieldB == "" {
return errors.New("Blank Field B")
}
return nil
}
Playground example if you need to specifically return an error

Cannot use &dashUrl (type *[]byte) as type *string in assignment

I'm trying to parse a form post that may be empty and if it is I will change the variable. Trying to use *string type. The problem I'm having is it dosen't convert for the dashUrl but does for the start_time
package main
import (
"encoding/base64"
"strconv"
"github.com/gocraft/web"
)
type YoutubeContext struct {
StartTime *float64 `json:"start_time"`
DashUrl *string `json:"dash_url"`
}
func (c *YoutubeContext) SetYoutubeContext(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {
if f, err := strconv.ParseFloat(req.FormValue("start_time"), 64); err == nil {
c.StartTime = &f
}
if dashUrl, dashUrlDecodeErr := base64.StdEncoding.DecodeString(req.FormValue("dash_url")); dashUrlDecodeErr == nil {
c.DashUrl = &dashUrl
}
}
func main() {
}
the error it shows is this
./test.go:19: cannot use &dashUrl (type *[]byte) as type *string in assignment
Was helped in the gophers slack chat, need to make a temporary variable
blah := string(dashUrl)
c.DashUrl = &blah

Resources