。(data_type)方法到底调用/做什么?

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.