提交 79a0e216 编写于 作者: A aarzilli 提交者: Derek Parker

proc: add iface.(data) syntax to access concrete value of an interface

With this syntax users do not need to type the concrete type of an
interface variable to access its contents. This also sidesteps the
problem where the serialization of a type by go/printer is different
from the one used for debug_info type names.

Updates #1328
上级 1b4c3183
......@@ -75,13 +75,27 @@ interface {}(*struct string) *"test"
error(*struct main.astruct) *{A: 1, B: 2}
```
To use a field of a struct contained inside an interface variable use a type assertion:
To use the contents of an interface variable use a type assertion:
```
(dlv) p iface1.(*main.astruct).B
2
```
Or just use the special `.(data)` type assertion:
```
(dlv) p iface1.(data).B
2
```
If the contents of the interface variable are a struct or a pointer to struct the fields can also be accessed directly:
```
(dlv) p iface1.B
2
```
# Specifying package paths
Packages with the same name can be disambiguated by using the full package path. For example, if the application imports two packages, `some/package` and `some/other/package`, both defining a variable `A`, the two variables can be accessed using this syntax:
......
......@@ -254,6 +254,15 @@ func main() {
s4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
var iface2map interface{} = map[string]interface{}{
"a": map[string]interface{}{
"1": map[string]interface{}{
"x": 1,
"y": 2,
},
},
}
var amb1 = 1
runtime.Breakpoint()
for amb1 := 0; amb1 < 10; amb1++ {
......@@ -261,5 +270,5 @@ func main() {
}
runtime.Breakpoint()
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, errtypednil, emptyslice, emptymap, byteslice, runeslice, longstr, nilstruct, as2, as2.NonPointerRecieverMethod, s4)
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, errtypednil, emptyslice, emptymap, byteslice, runeslice, longstr, nilstruct, as2, as2.NonPointerRecieverMethod, s4, iface2map)
}
......@@ -640,12 +640,17 @@ func (scope *EvalScope) evalTypeAssert(node *ast.TypeAssertExpr) (*Variable, err
if xv.Children[0].Addr == 0 {
return nil, fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), exprToString(node.Type))
}
typ, err := scope.BinInfo.findTypeExpr(node.Type)
if err != nil {
return nil, err
}
if xv.Children[0].DwarfType.Common().Name != typ.Common().Name {
return nil, fmt.Errorf("interface conversion: %s is %s, not %s", xv.DwarfType.Common().Name, xv.Children[0].TypeString(), typ.Common().Name)
// Accept .(data) as a type assertion that always succeeds, so that users
// can access the data field of an interface without actually having to
// type the concrete type.
if idtyp, isident := node.Type.(*ast.Ident); !isident || idtyp.Name != "data" {
typ, err := scope.BinInfo.findTypeExpr(node.Type)
if err != nil {
return nil, err
}
if xv.Children[0].DwarfType.Common().Name != typ.Common().Name {
return nil, fmt.Errorf("interface conversion: %s is %s, not %s", xv.DwarfType.Common().Name, xv.Children[0].TypeString(), typ.Common().Name)
}
}
// loadInterface will set OnlyAddr for the data member since here we are
// passing false to loadData, however returning the variable with OnlyAddr
......
......@@ -798,6 +798,8 @@ func TestEvalExpression(t *testing.T) {
{"s2[0].NonPointerRecieverMethod", false, "main.astruct.NonPointerRecieverMethod", "main.astruct.NonPointerRecieverMethod", "func()", nil},
{"as2.Error", false, "main.(*astruct).Error", "main.(*astruct).Error", "func() string", nil},
{"as2.NonPointerRecieverMethod", false, "main.astruct.NonPointerRecieverMethod", "main.astruct.NonPointerRecieverMethod", "func()", nil},
{`iface2map.(data)`, false, "…", "…", "map[string]interface {}", nil},
}
ver, _ := goversion.Parse(runtime.Version())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册