Strange behavior for a pointer of an interface
I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why?
The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface()
has already reconstructed a interface which points at the struct{}{}
, just don't understand why it would fail.
go reflection interface go-reflect
add a comment |
I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why?
The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface()
has already reconstructed a interface which points at the struct{}{}
, just don't understand why it would fail.
go reflection interface go-reflect
add a comment |
I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why?
The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface()
has already reconstructed a interface which points at the struct{}{}
, just don't understand why it would fail.
go reflection interface go-reflect
I wrote 3 similar functions to figure out a strange behavior of Go's pointer reflection.
package main
import (
"reflect"
"fmt"
)
var i interface{} = struct {}{} // i is an interface which points to a struct
var ptr *interface{} = &i // ptr is i's pointer
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x).Elem())
}
func main1() { // f is asking for interface? OK, I'll use the struct's interface
structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
f(structValue)
}
func main2() { // Error? Let me try the struct's pointer
structPtr := reflect.ValueOf(ptr).Elem().Interface()
f(structPtr)
}
func main3() { // Why this one could succeed after New() ?
typ := reflect.ValueOf(ptr).Elem().Elem().Type()
newPtr := reflect.New(typ).Elem().Addr().Interface()
f(newPtr)
}
func main() {
//main1() // panic: reflect: call of reflect.Value.Elem on struct Value
//main2() // panic: reflect: call of reflect.Value.Elem on struct Value
main3() // OK. WHY???
}
Only main3 is working, the other 2 would panic. Why?
The key difference of 3 is that it creates a New Value.
As to main2, I think ValueOf().Elem().Interface()
has already reconstructed a interface which points at the struct{}{}
, just don't understand why it would fail.
go reflection interface go-reflect
go reflection interface go-reflect
edited Nov 25 '18 at 8:17
Flimzy
38k96497
38k96497
asked Nov 24 '18 at 22:52
user3201982user3201982
288
288
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1
and main2
will work as I think you expect if you f
change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f
in main3
is a *struct{}
. The function f
dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}
.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface()
and reflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem()
is the reflect value corresponding to i
. The call to Interface()
on this value returns an interface with the concrete value in i
.
The expression reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding to i
's concrete value. The call to Interface()
on this value returns an interface containing that concrete value.
The reason I wrote main1 and main2 is that I thoughtinterface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked byValueOf().Elem()
...
– user3201982
Nov 26 '18 at 3:16
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463058%2fstrange-behavior-for-a-pointer-of-an-interface%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1
and main2
will work as I think you expect if you f
change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f
in main3
is a *struct{}
. The function f
dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}
.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface()
and reflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem()
is the reflect value corresponding to i
. The call to Interface()
on this value returns an interface with the concrete value in i
.
The expression reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding to i
's concrete value. The call to Interface()
on this value returns an interface containing that concrete value.
The reason I wrote main1 and main2 is that I thoughtinterface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked byValueOf().Elem()
...
– user3201982
Nov 26 '18 at 3:16
add a comment |
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1
and main2
will work as I think you expect if you f
change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f
in main3
is a *struct{}
. The function f
dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}
.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface()
and reflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem()
is the reflect value corresponding to i
. The call to Interface()
on this value returns an interface with the concrete value in i
.
The expression reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding to i
's concrete value. The call to Interface()
on this value returns an interface containing that concrete value.
The reason I wrote main1 and main2 is that I thoughtinterface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked byValueOf().Elem()
...
– user3201982
Nov 26 '18 at 3:16
add a comment |
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1
and main2
will work as I think you expect if you f
change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f
in main3
is a *struct{}
. The function f
dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}
.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface()
and reflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem()
is the reflect value corresponding to i
. The call to Interface()
on this value returns an interface with the concrete value in i
.
The expression reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding to i
's concrete value. The call to Interface()
on this value returns an interface containing that concrete value.
The value returned from reflect.ValueOf holds the concrete value stored in the argument. If the argument is nil, the zero reflect.Value is returned.
To put this another way, the reflect.Value and the interface passed to reflect.Value have the same underlying value.
The functions main1
and main2
will work as I think you expect if you f
change to:
func f(x interface{}) { // print x's underlying value
fmt.Println(reflect.ValueOf(x))
}
The argument to f
in main3
is a *struct{}
. The function f
dereferences the pointer (with the call to Elem()) and prints the reflect value for the struct{}
.
One point that might be confusing is that reflect.ValueOf(ptr).Elem().Elem().Interface()
and reflect.ValueOf(ptr).Elem().Interface()
return an interface with the same concrete value.
The expression reflect.ValueOf(ptr).Elem()
is the reflect value corresponding to i
. The call to Interface()
on this value returns an interface with the concrete value in i
.
The expression reflect.ValueOf(ptr).Elem().Elem()
is the reflect value corresponding to i
's concrete value. The call to Interface()
on this value returns an interface containing that concrete value.
edited Nov 25 '18 at 4:34
answered Nov 25 '18 at 2:12
ThunderCatThunderCat
50.7k46482
50.7k46482
The reason I wrote main1 and main2 is that I thoughtinterface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked byValueOf().Elem()
...
– user3201982
Nov 26 '18 at 3:16
add a comment |
The reason I wrote main1 and main2 is that I thoughtinterface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked byValueOf().Elem()
...
– user3201982
Nov 26 '18 at 3:16
The reason I wrote main1 and main2 is that I thought
interface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked by ValueOf().Elem()
...– user3201982
Nov 26 '18 at 3:16
The reason I wrote main1 and main2 is that I thought
interface {}
is a special kind of pointer. Or, isn't it, in Golang? So an interface should be able to invoked by ValueOf().Elem()
...– user3201982
Nov 26 '18 at 3:16
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463058%2fstrange-behavior-for-a-pointer-of-an-interface%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown