I want to instantiate an object in Go using reflection and call a method on it. However, I have no idea how to do this. I have tried something, but it does not work.
type foo struct {
name string
}
func (f *foo) Bar() {
f.name = "baz"
fmt.Println("hi " + f.name)
}
func main() {
t := reflect.TypeOf(&foo{})
fooElement := reflect.New(t).Elem()
fooElement.MethodByName("Bar").Call([]reflect.Value{})
}
reflect.New works exactly like the new function, in that it returns an allocated pointer to the given type. This means you want pass the struct, not a pointer to the struct, to reflect.TypeOf.
t := reflect.TypeOf(foo{})
fooV := reflect.New(t)
Since you now have a pointer value of the correct type, you can call the method directly:
fooV.MethodByName("Bar").Call(nil)
https://play.golang.org/p/Aehrls4A8xB
Related
I'm a bit perplexed by this go code. I have a struct (Outer) with an embedded struct (Inner), but when I initialize Outer, I intentionally leave the embedded struct uninitialized.
type Inner struct {
value int
}
func (i *Inner) MyFunc() string {
return "inner"
}
func (i *Inner) OnlyInner() string {
return "only inner stuff"
}
type Outer struct {
*Inner
}
func (o *Outer) MyFunc() string {
return "outer"
}
func main() {
// embedded struct is *not* initialized
o := &Outer{}
fmt.Println(o.Inner)
fmt.Println(o.Inner.MyFunc())
fmt.Println(o.Inner.OnlyInner())
//fmt.Println(o.Inner.value)
}
Output:
<nil>
inner
only inner stuff
And if I uncomment the last line (with o.Inner.value), I get a nil pointer dereference error.
What's up here? The effective go page says (https://golang.org/doc/effective_go.html#embedding):
When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one.
It seems like in my case, the inner type is <nil>, yet the method calls execute without problem. What's going on under the hood?
A method can be called with a nil receiver, as long as you do not dereference the receiver itself.
This means that the following works playground:
package main
import (
"fmt"
)
type foo struct {
val int
}
func (f *foo) Print() {
fmt.Println("Receiver:", f)
}
func (f *foo) PrintVal() {
fmt.Println("Val: ", f.val)
}
func main() {
var f *foo
f.Print()
//f.PrintVal()
}
f.Print() works without issues since we're just printing a pointer, we're not trying to dereference it.
However, f.PrintVal attempts to dereference a nil pointer, causing a panic.
When in doubt, remember that the methods in this example are equivalent to functions that take the receiver as first parameter:
func Print(f *foo)
func PrintVal(f *foo)
This is mentioned in the spec under method declarations:
The type of a method is the type of a function with the receiver as
first argument. For instance, the method Scale has type
func(p *Point, factor float64)
However, a function declared this way
is not a method.
This makes it clear that the receiver is nothing special, it can be nil as long as you don't dereference it.
The methods of the uninitialized struct are being called with a nil-receiver. If in the methods used that receiver you would get a panic. It is valid to call a method using a nil receiver, and the method could modify its behavior by checking if the receiver is nil.
I've seen this asked here before. But I don't understand the answers.
How do I call a method from a string value. So if the
I have many methods that are
func (c *something) whateverName(whatever map[string]interface{}) {
}
Same argument type in each one. no returns etc... Literally the only difference in the method name.
I'm looking to do something like this, and I just can't get it to work. I just want to call the correct method from the value of "var myMethod string":
func (c something) foo(m map[string]interface{}) {
fmt.Println("foo..")
//do something with m
}
func main() {
myMethod := "foo"
message := make(map[string]interface{})
//fill message with stuff...
c := something{} //this is just a hypothetical example...
vt := reflect.ValueOf(c)
vm := vt.MethodByName(myMethod)
vm.Call([]reflect.Value{reflect.ValueOf(message)})
}
I'm obviously not understanding how reflection works.
Your example works if you export the method. Change foo to Foo:
type something struct{}
func (c something) Foo(m map[string]interface{}) {
fmt.Println("Foo..")
//do something with m
}
func main() {
myMethod := "Foo"
message := make(map[string]interface{})
//fill message with stuff...
c := something{} //this is just a hypothetical example...
vt := reflect.ValueOf(c)
vm := vt.MethodByName(myMethod)
vm.Call([]reflect.Value{reflect.ValueOf(message)})
}
This will output (try it on the Go Playground):
Foo..
Also note that in this example Foo() has value receiver: c something. If the method has a pointer receiver such as c *something, you need to have a pointer value to start with, because a method with a pointer receiver is not in the method set of the non-pointer type.
See related: Call functions with special prefix/suffix
If I have function like this
func TestMethod ( d interface{} ) {
}
If I am calling this as
TestMethod("syz")
Is this pass by value or pass by pointer ?
To summarise some of the discussion in the comments and answer the question:
In go everything in Go is passed by value. In this case the value is an interface type, which is represented as a pointer to the data and a pointer to the type of the interface.
This can be verified by running the following snippet (https://play.golang.org/p/9xTsetTDfZq):
func main() {
var s string = "syz"
read(s)
}
//go:noinline
func read(i interface{}) {
println(i)
}
which will return (0x999c0,0x41a788), one pointer to the data and one pointer to the type of interface.
Updated: Answer and comments above are correct. Just a lite bit of extra information.
Some theory
Passing by reference enables function members, methods, properties,
indexers, operators, and constructors to change the value of the
parameters and have that change persist in the calling environment.
Little code sniped to check how function calls work in GO for pointers
package main_test
import (
"testing"
)
func MyMethod(d interface{}) {
// assume that we received a pointer to string
// here we reassign pointer
newStr := "bar"
d = &newStr
}
func TestValueVsReference(t *testing.T) {
data := "foo"
dataRef := &data
// sending poiner to sting into function that reassigns that pointer in its body
MyMethod(dataRef)
// check is pointer we sent changed
if *dataRef != "foo" {
t.Errorf("want %q, got %q", "bar", *dataRef)
}
// no error, our outer pointer was not changed inside function
// confirms that pointer was sent as value
}
Say I have structs like so:
type Foo struct {
F string `zoom:"1"`
}
type Bar struct {
F string `zoom:"2"`
}
type Baz struct {
F string `zoom:"3"`
}
Say I wanted to create a func that can extract the f field from each struct, it might look like:
func extractField(s []struct{}){
for _, v := range s {
t := reflect.TypeOf(v{})
f, _ := t.FieldByName("F")
v, ok := f.Tag.Lookup("zoom")
}
}
is there a way to pass the structs to extractField? If I do this:
extractField([]struct{}{Foo, Bar, Baz})
I get this error:
Type Foo is not an expression
Type Bar is not an expression
Type Baz is not an expression
I just want to pass the 3 structs to the extractField func.
The only way I could figure out how to do this, is like so:
type Foo struct {
F string `zoom:"1"`
}
type Bar struct {
F string `zoom:"2"`
}
type Baz struct {
F string `zoom:"3"`
}
func extractField(s []interface{}){
for _, v := range s {
t := reflect.TypeOf(v)
f, _ := t.FieldByName("F")
v, ok := f.Tag.Lookup("zoom")
fmt.Println(v,ok)
}
}
func main(){
extractField([]interface{}{Foo{},Bar{},Baz{}}) // <<<< here
}
not sure if there is a way to pass a struct without "instantiating it" first.
The original code looks like it follows a JavaScript approach, where a function would mutate an object. Go is a little bit different, where it's more common to self-mutate.
For example:
type Generic struct {
field string
}
func (generic *Generic) Value () string {
return generic.field
}
someObject := &Generic{
field: "some value",
}
log.Print(someObject.Value()) // Outputs "some value"
If you're coming from the JavaScript world, think of structs a little bit like an object/class that can contain attributes and functions. Structs are merely a definition until an instance is instantiated. This differs from JavaScript where the definition of the object and the data are both defined at the same time.
As the other answer points out, an interface is another similar approach to dealing with this.
Clarification
In JavaScript terms, the OP is attempting to do something akin to:
class Foo {...}
class Bar {...}
class Baz {...}
extractField(Foo, Bar, Baz)
In JS-speak, this would pass a class definition to the extractField method. You would still have to instantiate an instance of a class if you want to manipulate/read from it, like:
extractField(new Foo(), new Bar(), new Baz())
This is basically what is being accomplished with
extractField([]interface{}{Foo{},Bar{},Baz{}})
I think the problem you're running into is the Foo/Bar/Baz structs are instantiated, but the nested F struct is not.
The overall problem seems like a much better match for an interface type.
type HasF interface {
GetF() string
}
It's easy enough to define these methods, e.g.
func (foo Foo) GetF() string { return foo.F }
Your method to iterate over them becomes almost trivial
func extractField(s []HasF) {
for _, v := range s {
fmt.Printf(v.GetF())
}
}
func main() {
extractField([]HasF{Foo{},Bar{},Baz{}})
}
https://play.golang.org/p/uw0T7TGVC0n has a complete version of this.
Can an instance of a go type change its underlying value? Thanks to a previous question I know I can make my function's receiver a pointer and change struct fields if my type is a struct.
However, I'm interesting in changing the underlying type's value. Consider a small program like this
type Foo string
func (f *Foo) ChangeMe() {
val := Foo("Hello World")
f = &val
//fmt.Println(*f)
}
func main() {
f := Foo("Nope")
f.ChangeMe()
fmt.Println(f)
}
My naive assumption was "OK, I've created a new Foo("Hello World") and then pointed f at it. Since receiver is a pointer (*Foo), this should change the value in main().
However, this does not work. The above program still prints out "Nope"
Interested both in what my incorrect assumption about go are, and any techniques for achieving what I want to do.
You're assigning a new pointer value to f instead of dereferencing it.
Dereference f and assign a new string value:
func (f *Foo) ChangeMe() {
*f = Foo("Hello World")
}