简体   繁体   中英

What exactly does .(data_type) method called/do?

I came a cross a piece of code that used .(string) method. Not knowing what this is called I had difficulties searching for it.

Here is my try to understand it:

package main

import "fmt"
import "reflect"

func main(){
    var b interface{}
    b = "silly"

    fmt.Println(reflect.TypeOf(b.(string))) // we know that b 
                                            // is a string                     
                                            // at compile time

    fmt.Println(reflect.TypeOf(b))          // we do not

}

Result:

string
string

However, I think that reflect.TypeOf takes place at run time, while .(string) would tell the compiler that b is indeed a string, and this could be used to tell the compiler that a variable is of certain type. Is my understanding right?

goplayground

b.(string) is called a type assertion . As written in Effective Go :

A type assertion takes an interface value and extracts from it a value of the specified explicit type.

So, yes, the value you get from a type assertion is not an interface value, but is of the explicit type. You can also test if the type assertion was successful by adding an untyped boolean value:

s, ok := b.(string) // s is of type string
if !ok {
    // b did not contain a value of type string!
}

Edit:

To explain further to clear out any possible misunderstanding:

A type assertion doesn't "tell Go that b is a string" as you suggested. What it does is that it will, in run time, try to extract a string from b , and panic if b contains some other type (unless assigning the optional bool value).

The value that you get from the assertion will indeed be of type string , allowing you to do things like slicing (you cannot slice an interface value) or checking its len .

The previous answer is correct. But I submit this as more like what happens in practice. The .(type) syntax is usually used with type names in the cases of a switch. In this example, I (integer expr), B (bool expr), and Bop (binary op) are type names.

func commute (e Expr) (r Expr, d bool) {
    switch exp:= e.(type) {
        case I: r,d = exp,false
        case B: r,d = exp,false
        case Bop: r,d = Bop{exp.op, exp.right, exp.left},true
        default: r,d = e,false
    }
    return
}

This isn't unsafe like a C cast, because inside the case statement you are guaranteed to have the matching type. I see this quite a bit when reading a channel, where the type of the channel is an interface that all the cases implement.

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