2

http.HandleFunc("/", handler) // each request calls handler

    log.Fatal(http.ListenAndServe("localhost:8000", nil))

}

func handler(w http.ResponseWriter, r *http.Request) {

    fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)

}

func Exit(code int)

应用程序马上退出。

defer函数不会执行。

总结起来log.Fatal函数完成:

打印输出内容

退出应用程序

defer函数不会执行

Panic

函数立刻停止执行 (注意是函数本身,不是应用程序停止)

defer函数被执行

返回给调用者(caller)

调用者函数假装也收到了一个panic函数,从而

4.1 立即停止执行当前函数

4.2 它defer函数被执行

4.3 返回给它的调用者(caller)

...(递归重复上述步骤,直到最上层函数)

应用程序停止。

panic的行为

"sync"

var mu sync.Mutex

var count int

func handler(w http.ResponseWriter, r *http.Request) {

    mu.Lock()

    count++

    mu.Unlock()

    fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)

}

在这些代码的背后,服务器每一次接收请求处理时都会另起一个goroutine,这样服务器就可以同一时间处理多个请求。

switch coinflip() {

case "heads":

    heads++

case "tails":

    tails++

default:

    fmt.Println("landed on edge!")

}

Go语言并不需要显式地在每一个case后写break,语言默认执行完case后的逻辑语句会自动退出。

如果你想要相邻的几个case都执行同一逻辑的话,需要自己显式地写上一个fallthrough语句来覆盖这种默认行为。不过fallthrough语句在一般的程序中很少用到。

Go语言里的switch还可以不带操作对象(译注:switch不带操作对象时默认用true值代替

func Signum(x int) int {

    switch {

    case x > 0:

        return +1

    default:

        return 0

    case x < 0:

        return -1

    }

}

像for和if控制语句一样,switch也可以紧跟一个简短的变量声明,一个自增表达式、赋值语句,或者一个函数调用

和其它语言中的break和continue一样,break会中断当前的循环,并开始执行循环之后的内容,而continue会跳过当前循环,并开始执行下一次循环。

这两个语句除了可以控制for循环,还可以用来控制switch和select语句

命名类型: 类型声明使得我们可以很方便地给一个特殊类型一个名字

type Point struct {

    X, Y int

}

var p Point

指针是可见的内存地址,&操作符可以返回一个变量的内存地址,并且*操作符可以获取指针指向的变量内容

方法是和命名类型关联的一类函数。Go语言里比较特殊的是方法可以被关联到任意一种命名类型。

接口是一种抽象类型,这种类型可以让我们以同样的方式来处理不同的固有类型,不用关心它们的具体实现,而只需要关注它们提供的方法。

命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。

指针对应的数据类型是*int,指针被称之为“指向int类型的指针”。

对于聚合类型每个成员——比如结构体的每个字段、或者是数组的每个元素——也都是对应一个变量,因此可以被取地址。

任何类型的指针的零值都是nil

在Go语言中,返回函数中局部变量的地址也是安全的。

var n = flag.Bool("n", false, "omit trailing newline")

var sep = flag.String("s", " ", "separator")

  flag.Parse()

对于非标志参数的普通命令行参数可以通过调用flag.Args()函数来访问,返回值对应对应一个字符串类型的slice。

如果在flag.Parse函数解析命令行参数时遇到错误,默认将打印相关的提示信息,然后调用os.Exit(2)终止程序。

达式new(T)将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址,返回的指针类型为*T。

p := new(int)  // p, *int 类型, 指向匿名的 int 变量

fmt.Println(*p) // "0"

*p = 2          // 设置 int 匿名变量的值为 2

fmt.Println(*p) // "2"

每次调用new函数都是返回一个新的变量的地址,

当然也可能有特殊情况:如果两个类型都是空的,也就是说类型的大小是0,例如struct{}和 [0]int, 有可能有相同的地址(依赖具体的语言实现)

由于new只是一个预定义的函数,它并不是一个关键字,因此我们可以将new名字重新定义为别的类型。例如下面的例子:

func delta(old, new int) int { return new - old }

由于new被定义为int类型的变量名,因此在delta函数内部是无法使用内置的new函数的。

img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),

        blackIndex)

函数的有右小括弧也可以另起一行缩进,同时为了防止编译器在行尾自动插入分号而导致的编译错误,可以在末尾的参数变量后面显式插入逗号

最后插入的逗号不会导致编译错误,这是Go编译器的一个特性

那么Go语言的自动垃圾收集器是如何知道一个变量是何时可以被回收的呢?这里我们可以避开完整的技术细节,基本的实现思路是,从每个包级的变量和每个当前运行函数的每一个局部变量开始,通过指针或引用的访问路径遍历,是否可以找到该变量。如果不存在这样的访问路径,那么说明该变量是不可达的,也就是说它是否存在并不会影响程序后续的计算结果。

编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,但可能令人惊讶的是,这个选择并不是由用var还是new声明变量的方式决定的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容