Velvet Star Monitor

Standout celebrity highlights with iconic style.

general

Golang Cast interface to struct

Writer Mia Lopez

Hi I'm trying to retrieve the function/method of one struct but I'm using an interface as parameter and using this interface I'm trying to access the function of the struct. To demonstrate what I want below is my code

// Here I'm trying to use "GetValue" a function of RedisConnection but since "c" is an interface it doesn't know that I'm trying to access the RedisConnection function. How Do I fix this?
func GetRedisValue(c Connection, key string) (string, error) { value, err := c.GetValue(key) return value, err
}
// Connection ...
type Connection interface { GetClient() (*redis.Client, error)
}
// RedisConnection ...
type RedisConnection struct {}
// NewRedisConnection ...
func NewRedisConnection() Connection { return RedisConnection{}
}
// GetClient ...
func (r RedisConnection) GetClient() (*redis.Client, error) { redisHost := "localhost" redisPort := "6379" if os.Getenv("REDIS_HOST") != "" { redisHost = os.Getenv("REDIS_HOST") } if os.Getenv("REDIS_PORT") != "" { redisPort = os.Getenv("REDIS_PORT") } client := redis.NewClient(&redis.Options{ Addr: redisHost + ":" + redisPort, Password: "", // no password set DB: 0, // use default DB }) return client, nil
}
// GetValue ...
func (r RedisConnection) GetValue(key string) (string, error) { client, e := r.GetClient() result, err := client.Ping().Result() return result, nil
}
1

2 Answers

To answer the question directly, i.e., to cast an interface into a concrete type, you do:

v = i.(T)

where i is the interface and T is the concrete type. It will panic if the underlying type is not T. To have a safe cast, you use:

v, ok = i.(T)

and if the underlying type is not T, ok is set to false, otherwise true. Note that T can also be an interface type and if it is, the code cast i into a new interface instead of a concrete type.

And please be noted, casting an interface is likely a symbol of bad design. As in your code, you should ask yourself, does your custom interface Connection solely requires GetClient or does it always requires a GetValue? Does your GetRedisValue function requires a Connection or does it always wants a concrete struct?

Change your code accordingly.

1

Your Connection interface:

type Connection interface { GetClient() (*redis.Client, error)
}

only says that there is a GetClient method, it says nothing about supporting GetValue.

If you want to call GetValue on a Connection like this:

func GetRedisValue(c Connection, key string) (string, error) { value, err := c.GetValue(key) return value, err
}

then you should include GetValue in the interface:

type Connection interface { GetClient() (*redis.Client, error) GetValue(string) (string, error) // <-------------------
}

Now you're saying that all Connections will support the GetValue method that you want to use.

2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy