I'm to create an object (whatever it is) satisfying certain interface 
dynamically. There's no way I can do it so I'm thinking maybe I can add a 
func in `reflect` package to cover my need.

The `reflect.StructOf`  func creates a struct type but without adding 
methods which gives a good example. I imitated and created an `InterfaceOf` 
func. However the following error appeared,

```
unexpected fault address 0xc0000b8120 fatal error: fault [signal SIGSEGV: 
segmentation violation code=0x2 addr=0xc0000b8120 pc=0xc0000b8120]
```

Here is the file I added into the `reflect` package,

```golang
package reflect

import (
    "sort"
    "unsafe"
)

type InterfaceMethod struct {
    Name string
    Func Value
}

func InterfaceOf(funcs []InterfaceMethod) Value {
    if len(funcs) == 0 {
        return New(TypeOf("Interface {}"))
    }

    var (
        repr     = []byte("struct { /* non-invertible */ }")
        hash     = fnv1(0, []byte("struct { /* non-invertible */ }")...)
        size     uintptr
        typalign uint8
        methods  []method
    )

    // add sorted methods here
    {
        for idx := range funcs {
            if funcs[idx].Func.Type().Kind() != Func {
                panic("funcs contains non-func")
            }
            c := funcs[idx].Name[0]
            if !('A' <= c && c <= 'Z') {
                panic("funcs contains unexported func")
            }
        }

        sort.Slice(funcs, func(i, j int) bool {
            return funcs[i].Name < funcs[j].Name
        })

        for idx := range funcs {
            ft := funcs[idx].Func.Type().common()
            ft.uncommon()

            ifn := funcs[idx].Func
            methods = append(methods, method{
                name: resolveReflectName(newName(funcs[idx].Name, "", 
true)),
                mtyp: resolveReflectType(ft),
                ifn:  resolveReflectText(unsafe.Pointer(&ifn)),
                tfn:  resolveReflectText(unsafe.Pointer(&ifn)),
            })
        }
    }

    var typ *structType
    var ut *uncommonType

    {
        // A *rtype representing a struct is followed directly in memory by 
an
        // array of method objects representing the methods attached to the
        // struct. To get the same layout for a run time generated type, we
        // need an array directly following the uncommonType memory.
        // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
        tt := New(StructOf([]StructField{
            {Name: "S", Type: TypeOf(structType{})},
            {Name: "U", Type: TypeOf(uncommonType{})},
            {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
        }))

        typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer())
        ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer())

        copy(tt.Elem().Field(2).Slice(0, 
len(methods)).Interface().([]method), methods)
    }

    ut.mcount = uint16(len(methods))
    ut.xcount = ut.mcount // we only have exported methods
    ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
    str := string(repr)

    // Round the size up to be a multiple of the alignment.
    size = align(size, uintptr(typalign))

    // Make the struct type.
    var istruct any = struct{}{}
    prototype := *(**structType)(unsafe.Pointer(&istruct))
    *typ = *prototype

    typ.str = resolveReflectName(newName(str, "", false))
    typ.tflag = 0 // TODO: set tflagRegularMemory
    typ.hash = hash
    typ.size = size
    typ.ptrdata = typeptrdata(typ.common())
    typ.align = typalign
    typ.fieldAlign = typalign
    typ.ptrToThis = 0
    typ.tflag |= tflagUncommon

    {
        typ.kind &^= kindGCProg
        bv := new(bitVector)
        addTypeBits(bv, 0, typ.common())
        if len(bv.data) > 0 {
            typ.gcdata = &bv.data[0]
        }
    }

    typ.equal = nil

    typ.kind &^= kindDirectIface

    return Zero(&typ.rtype)
}

```

And a corresponding testing file,

```golang
package main

import (
    "fmt"
    "reflect"
    "testing"
)

func TestInterfaceOf(t *testing.T) {
    type AliceInterface interface {
        BobMethod() (error, string)
    }
    Alice := reflect.TypeOf((*AliceInterface)(nil)).Elem()
    Bob := Alice.Method(0)

    Carol := reflect.MakeFunc(Bob.Type, func(args []reflect.Value) 
[]reflect.Value {
        fmt.Println("[wow]")
        nilError := reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())
        return []reflect.Value{nilError, reflect.ValueOf("haha")}
    })

    Dan := reflect.InterfaceOf([]reflect.InterfaceMethod{
        {
            Name: "BobMethod",
            Func: Carol,
        },
    })

    Dan.Method(0).Call([]reflect.Value{}) // panic

    dan := Dan.Interface().(AliceInterface)
    dan.BobMethod() // also panic

}
```

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/a13e8bd6-f36d-4806-aa29-748942c6d2d7n%40googlegroups.com.

Reply via email to