go学习笔记(一)

变量

var num int;var num int = 1,var a,b int;var a,b int = 1,2;var a = 1;_,b=1,2;

1,:=这个符号直接取代了var和type,这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用var方式来定义全局变量。

2,_(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。

3,Go对于已声明但未使用的变量会在编译阶段报错

常量

const Pi=3.1415926;const i =10000;const MaxThread=10;const prefix ="astaxie_"

所谓常量,也就是在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。在Go程序中,常量可定义为数值、布尔值或字符串等类型

数值

整数类型有无符号和带符号两种。Go同时支持int和uint,这两种类型的长度相同,但具体长度取决于不同编译器的实现。Go里面也有直接定义好位数的类型:rune, int8, int16, int32, int64和byte, uint8, uint16, uint32, uint64。其中rune是int32的别称,byte是uint8的别称。

注:这些类型的变量之间不允许互相赋值或操作,不然会在编译时引起编译器报错。另外,尽管int的长度是32 bit, 但int 与 int32并不可以互用。浮点数的类型有float32和float64两种(没有float类型),默认是float64。

字符串

Go中的字符串都是采用UTF-8字符集编码。字符串是用一对双引号("")或反引号(` `)括起来定义,它的类型是string。

注:在Go中字符串是不可变的,若一定要修改,可以将字符串 s 转换为 []byte 类型,再转换回 string 类型,Go中可以使用+操作符来连接两个字符串,字符串虽不能更改,但可进行切片操作,如果要声明一个多行的字符串怎么办?可以通过`来声明。

array、slice、map

array就是数组,var arr [n]type,长度也是数组类型的一部分,因此[3]int与[4]int是不同的类型,数组也就不能改变长度。数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果要使用指针,那么就需要用到后面介绍的slice类型了。

“动态数组”,在Go里面这种数据结构叫slice,slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。slice可以从一个数组或一个已经存在的slice中再次声明。slice通过array[i:j]来获取,其中i是数组的开始位置,j是结束位置,但不包含array[j],它的长度是j-i,类似于python的切片或者c++的vector。

从概念上面来说slice像一个结构体,这个结构体包含了三个元素:

一个指针,指向数组中slice指定的开始位置。

长度,即slice的长度。

最大长度,也就是slice开始位置到数组的最后位置的长度。

对于slice有几个有用的内置函数:

len 获取slice的长度

cap 获取slice的最大容量

append 向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice

copy 函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数

注:append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。 但当slice中没有剩余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响。

注意:slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。slice是引用类型,所以当引用改变其中元素的值时,其它的所有引用都会改变该值。

map类似python中的字典。声明举例:var numbersmap [string]int,numbers =make(map[string]int)。

使用map过程中需要注意的几点:

map是无序的,每次打印出来的map都会不一样,它不能通过index获取,而必须通过key获取

map的长度是不固定的,也就是和slice一样,也是一种引用类型

内置的len函数同样适用于map,返回map拥有的key的数量

map的值可以很方便的修改,通过numbers["one"]=11可以很容易的把key为one的字典值改为11

map和其他基本型别不同,它不是thread-safe,在多个go-routine存取时,必须使用mutex lock机制

map的初始化可以通过key:val的方式初始化值,同时map内置有判断是否存在key的方式

通过delete删除map的元素:

map也是一种引用类型,如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变

make、new操作

make用于内建类型(map、slice 和channel)的内存分配。new用于各种类型的内存分配。

注:new返回指针。make返回初始化后的(非零)值。make 只能为 slice、map或 channel 类型分配内存并初始化,同时返回一个有初始值的 slice、map 或 channel 类型引用,不是指针。内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针。

流程控制

Go里面if条件判断语句中不需要括号,Go的if还有一个强大的地方就是条件判断语句里面允许声明一个变量,这个变量的作用域只能在该条件逻辑块内,其他地方就不起作用了,比如if x=1;x>0{执行体}。

goto类似c语言中的goto,

for,在循环里面有两个关键操作break和continue ,break操作是跳出当前循环,continue是跳过本次循环。当嵌套过深的时候,break可以配合标签使用,即跳转至标签所指定的位置,break和continue还可以跟着标号,用来跳到多重循环中的外层循环。

switch,类似与c的switch,Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch,但是可以使用fallthrough强制执行后面的case代码。

函数

注:函数可以返回多个值。Go函数支持变参,如 func myfunc(arg...int) {}。

传值,当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。

传指针使得多个函数能操作同一个对象。传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。Go语言中channel,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)

defer,Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。

函数作为值、类型。在Go中函数也是一种变量,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。函数当做值和类型在我们写一些通用接口的时候非常有用。

Panic和Recover

Panic是一个内建函数,可以中断原有的控制流程,进入一个panic状态中。当函数F调用panic,函数F的执行被中断,但是F中的延迟函数defer会正常执行,然后F返回到调用它的地方。在调用的地方,F的行为就像调用了panic。这一过程继续向上,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。panic可以直接调用panic产生。也可以由运行时错误产生,例如访问越界的数组。

Recover是一个内建的函数,可以让进入panic状态的goroutine恢复过来。recover仅在延迟函数defer中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic状态,调用recover可以捕获到panic的输入值,并且恢复正常的执行。

main函数和init函数

Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。虽然一个package里面可以写任意多个init函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个package中每个文件只写一个init函数。

Go程序会自动调用init()和main(),所以你不需要在任何地方调用这两个函数。每个package中的init函数都是可选的,但package main就必须包含一个main函数。

程序的初始化和执行都起始于main包。如果main包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数。下图详细地解释了整个执行过程:

import这个命令用来导入包文件,类似于include,

import . "fmt" 点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名

import f “fmt” 别名 fmt.Printf()->f.Printf()

import _ “fmt” _操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。

struct类型

和C语言类似

定义:

type person struct {

        name strin

        gage int

}

1.按照顺序提供初始化值

P := person{"Tom", 25}

2.通过field:value的方式初始化,这样可以任意顺序

P := person{age:24, name:"Tom"}

3.当然也可以通过new函数分配一个指针,此处P的类型为*person

P := new(person)

匿名字段:Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。通过匿名访问和修改字段相当的有用,但是不仅仅是struct字段哦,所有的内置类型(int string等)和自定义类型都是可以作为匿名字段的。

注:结构中匿名字段和结构本身字段重名,Go里面很简单的解决了这个问题,最外层的优先访问

面向对象

通俗的说就是给struct绑定了函数,函数接收者可以时值copy,也可以是指针,

method的语法如下:

func (r ReceiverType) funcName(parameters) (results)

在使用method的时候重要注意几点

虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样

method里面可以访问接收者的字段

调用method通过.访问,就像struct里面访问字段一样

method 重写,继承。

举例

package main

import "fmt"

type Human struct {

    name  string

    age  int

    phone string // Human类型拥有的字段

}

type Student struct {

    Human

    school string

    phone  string

}

type Employee struct {

    Human      // 匿名字段Human

    speciality string

    phone      string // 雇员的phone字段

}

func (h Human) say() {

    fmt.Println(h.name, h.age, h.phone)

}+++

func (h Employee) say() {

    fmt.Println(h.name, h.age, h.phone, h.speciality, h.Human.phone)

}

func main() {

    Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}

    Tom := Student{Human{"Tom", 18, "123-456-189"}, "yichuan", "666"}

    Tom.say()

    Bob.say()

    fmt.Println(Tom.phone, Tom.Human.phone)


注:以上笔记基本来自

https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/preface.md

作为业余爱好仅仅记录了一些注意点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容