Andrea Golin
Andrea Golin

Reputation: 3559

How to access struct property from interface used as generic

Maybe i am just over complicating my code but i am trying to get a better understanding of how interfaces and structs work in golang.

Basically, i am storing elements that satisfy interface I inside an hash table. As all the items that satisfy I can be contained inside an I element, i thought i could be using I as a kind of "generic" interface, stuff them inside a hashmap, then pull them out later and access the "underlyng" struct methond from there.

Unfortunately, after pulling the element out, i found out that i cannot call the struct method, as element is of Interface type, and the "original" struct is not accessible anymore.

Is there a way to get a clean and simple access to the struct that satisfy I?

This is my code, it throws a "value.name undefined (type I has no field or method name)" inside the for loop:

/**
 * Define the interface
 */
type I interface{
    test()
}

/**
 * Define the struct
 */
type S struct{
    name string
}

/**
 *  S now implements the I interface
 */
func (s S) test(){}

func main(){

    /**
     * Declare and initialize s S
     */
    s := S{name:"testName"}

    /**
     * Create hash table
     * It CAN contains S types as they satisfy I interface
     * Assign and index to s S
     */
    testMap := make(map[string]I)
    testMap["testIndex"] = s

    /**
     * Test the map length
     */
    fmt.Printf("Test map length: %d\r\n", len(testMap))

    for _, value := range testMap{

        /**
         * This is where the error is thrown, value is of Interface type, and it is not aware of any "name" property
         */
        fmt.Printf("map element name: %s\r\n", value.name)
    }

}

Upvotes: 3

Views: 3344

Answers (2)

gao
gao

Reputation: 846

I think what you need is type swithes as in tour of go

And you can access underlying structs as below:

for _, value := range testMap {
    switch v := value.(type) {
    case S:
        fmt.Printf("map element name: %s\r\n", v.name)
        // TODO: add other types here
    }
}

Upvotes: 1

Jonathan Hall
Jonathan Hall

Reputation: 79744

You should add an accessor to your interface:

type I interface {
    test()
    Name() string
}

Then make sure your struct implements this method:

func (s S) Name() string {
    return s.name
}

And then access the name using the accessor method:

        fmt.Printf("map element name: %s\r\n", value.Name())

Upvotes: 4

Related Questions