简体   繁体   中英

Can you type assert an anonymous struct?

I want to do something like this:

type Struct1 struct {
    var1 int
}

type i interface {
    display()
}

func (s Struct1) display() {
    fmt.Println(s.var1)
}

func check(i interface{}) {
    i.(Struct1).display()
}

func main() {
    data := struct {
        int
    }{
        2,
    }

    check(interface{}(data))
}

I have a function in an external dependency that accepts and returns interface{} type. That function type asserts a struct(let's say Struct1). The struct has fields that are not exported to I cannot create an instance of it to pass to the function. I know what fields it has, their names and types. Is it possible to send data not of type Struct1 that can be asserted to become Struct1 type.

Can you type assert an anonymous struct?

Of course you can! But there are limitations.

Some things that will work:

  1. Assert to a matching anonymous struct:

     x := interface{}(struct { Count int }{Count: 5}) fmt.Printf("x's count: %d\\n", x.(struct{Count int}).Count) 

    Playground .

  2. Assert to an interface:

      type Fooer interface { Foo() } type X struct {} func (x X) Foo() { fmt.Printf("X Fooed\\n") } func main() { x := interface{}(struct { X }{ X{} }) // An anonymous struct which embeds X x.(Fooer).Foo() } 

    Playground .

Some things that won't work:

  1. Assert to a matching anonymous struct from another package, with un-exported fields.

     x := url.UserPassword("foo","bar") fmt.Printf("Username: %s\\n", x.(struct{username string; password string; passwordSet bool}).username) 

    Playground .

What you try to do in your specific case is not possible. Even though the Struct1 and your anonymous struct have the same layout, they are different types for the Go compiler. Think of the time.Duration for example, it is actually just an int64 but you cannot use them interchangeably. This is done on purpose in Go. Other languages, like C, allow you to do all kinds of conversions and casts and will rarely give you a compiler error. This has shown to be a source of programmer errors and thus was done differently in Go.

To still give you a "solution" to your problem, just for completeness, here is a version that uses C-like unsafe casts to make your anonymous struct into a Struct1 :

package main

import (
    "fmt"
    "unsafe"
)

type S struct {
    i int
}

type I interface {
    display()
}

func (s S) display() {
    fmt.Println(s.i)
}

func check(i interface{}) {
    i.(S).display()
}

func main() {
    data := struct{ int }{2}
    // check(data) this will not work
    check(*((*S)(unsafe.Pointer(&data))))
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM