简体   繁体   English

识别存储在 go 接口中的实际类型

[英]Identifying the actual type being stored in a go interface

In the following code在下面的代码中

    var r io.Reader
    c, _ := net.Dial("tcp", ":8080")
    r = c 
    switch r.(type) {
    case io.Reader:
        fmt.Println("r implements the reader interface")
        // fallthrough
    case io.Writer:
        fmt.Println("r implements the writer interface")
    case net.Conn:
        fmt.Println("r implements the conn interface")
    }

the first case statement is the one that's always executed.第一个case语句是始终执行的语句。

If I uncomment fallthrough the code does not compile given that fallthrough is not allowed in a type switch如果我取消注释fallthrough则代码不会编译,因为类型开关中不允许fallthrough

If I am not wrong a go interface has 2 values:如果我没有错的话, go接口有 2 个值:

  • the actual TYPE (descriptor) stored in the interface (eg io.Writer , io.Reader etc)存储在接口中的实际 TYPE(描述符)(例如io.Writerio.Reader等)
  • the value stored in it存储在其中的值

Since r apparently satisfies all of the above case statements, what is the way of finding the exact type stored in r ?由于r显然满足上述所有case语句,那么找到存储在r的确切类型的方法是什么?

Is it only through reflection that this cone be done?这个锥体是通过反思才完成的吗?

The type switch as well as the type assertion may be used to check if an interface value holds a value of a concrete type (and at the same time extract a value of that concrete type).类型开关以及类型断言可用于检查接口值是否包含具体类型的值(并同时提取该具体类型的值)。 If the type you check (or type assert) is an interface type (and not a concrete type), the case will match (or the assertion will hold) if the concrete type implements the given interface type.如果您检查的类型(或类型断言)是接口类型(而不是具体类型),则如果具体类型实现给定的接口类型,则案例将匹配(或断言将成立)。

net.Conn is an interface that is a superset of both io.Reader and io.Writer . net.Conn是一个接口,它是io.Readerio.Writer的超集。 If something implements net.Conn , it automatically implements io.Reader and io.Writer as well, so if you check io.Reader first, that will match (if the type also implements net.Conn ).如果某些东西实现了net.Conn ,它net.Conn自动实现io.Readerio.Writer ,所以如果你先检查io.Reader ,那将匹配(如果类型也实现了net.Conn )。

If you want to use a type switch to check for implemented interfaces, check for net.Conn first, and if it's not implemented, list io.Reader and io.Writer later on.如果要使用类型开关检查实现的接口,请先检查net.Conn ,如果未实现,稍后列出io.Readerio.Writer

switch r.(type) {
case net.Conn:
    fmt.Println("r implements the conn interface")
case io.Reader:
    fmt.Println("r implements the reader interface")
case io.Writer:
    fmt.Println("r implements the writer interface")
}

If I am not wrong a go interface has 2 values:如果我没有错的话,go 接口有 2 个值:

  • the actual TYPE (descriptor) stored in the interface (eg io.Writer, io.Reader etc)存储在接口中的实际 TYPE(描述符)(例如 io.Writer、io.Reader 等)
  • the value stored in it存储在其中的值

You are not wrong but you miss a key point: the actual concrete type.你没有错,但你错过了一个关键点:实际的具体类型。 io.Conn and io.Reader are not concrete types, they are inteface types. io.Connio.Reader不是具体类型,它们是接口类型。

An example concrete type that may be returned by net.Dial() is *net.TCPConn . net.Dial()可能返回的一个具体类型示例是*net.TCPConn

Use this code to find the concrete type of the value:使用此代码查找值的具体类型:

var r io.Reader
c, _ := net.Dial("tcp", ":8080")
r = c 
fmt.Printf("The type of r is %T\n", r)

The reflect package can also be used to find the concrete type:反射包也可用于查找具体类型:

t := reflect.TypeOf(r)
fmt.Println("The type of or is", t)

Use separate if statements to check support for each interface.使用单独的 if 语句来检查对每个接口的支持。 A type switch cannot test for all interfaces because the switch continues on the the first type to match.类型交换机无法测试所有接口,因为交换机会继续匹配第一个类型。

if _, ok := r.(io.Reader); ok {
    // we know this already because r is an io.Reader
    fmt.Println("r implements the reader interface")
}
if _, ok := r.(io.Writer); ok {
    fmt.Println("r implements the writer interface")
}
if _. ok := r.(net.Conn); ok {
    fmt.Println("r implements the conn interface")
}

We know that the conditions in all of the if statements evaluate to true because the value in r satisfies the net.Conn interface.我们知道所有 if 语句中的条件评估为真,因为r的值满足net.Conn接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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