Go语言入门笔记

前端之家收集整理的这篇文章主要介绍了Go语言入门笔记前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

格式化

Go语言中为了防止格式化问题引发争论,制作了一个格式化工具gofmt,在写完代码之后只需要gofmt -w *.go就可以用统一的格式(比如对齐,缩进)来重写你的代码-w参数是重写你的文件,不加的话只会打印你的文件内容

命名

  • 一个包里面的变量如果要在包外可以被使用,首字母就必须是大写
  • 使用RPC调用的结构体里的参数也都需要首字母大写
  • 包名需要都小写
  • Go 中约定使用驼峰记法 MixedCaps 或 mixedCaps 而非下划线的方式来对多单词名称进行命名

分号

Go语言中语句也是由分号来结尾的,只是这些语句不显式的出现在源代码中,词法分析器会在编译过程中为每句语句的结尾添加上分号。

由于分号添加的规则,所以条件控制,循环,函数等语句的左大括号必须不能另起一行,否则会因为添加分号导致错误

控制结构

循环只有for

@H_301_36@// 如同 C 的 for 循环 for init; condition; post { } // 如同 C 的 while 循环 for condition { } // 如同 C 的 for(;;) 循环 for { }

若你想遍历数组、切片、字符串或者映射,或从信道中读取消息, range 子句能够帮你轻松实现循环。

@H_301_36@for key,value := range oldMap { newMap[key] = value }

可以省略第二个键,但是要省略第一个键必须用_

switch语法除了正常的判断值,还能判断变量类型:

@H_301_36@var t interface{} t = functionOfSomeType() switch t := t.(type) { default: fmt.Printf("unexpected type %T",t) // %T prints whatever type t has case bool: fmt.Printf("boolean %t\n",t) // t has type bool case int: fmt.Printf("integer %d\n",t) // t has type int case *bool: fmt.Printf("pointer to boolean %t\n",*t) // t has type *bool case *int: fmt.Printf("pointer to integer %d\n",*t) // t has type *int }

switch语法中的case语句自带break,所以不需要显式的写break

break也可以显式的指定跳转到的标签位置,比如:

@H_301_36@Loop: for n := 0; n < len(src); n += size { switch { case src[n] < sizeOne: if validateOnly { break } size = 1 update(src[n]) case src[n] < sizeTwo: if n+1 >= len(src) { err = errShortInput break Loop }

函数

  • Go里面的函数可以多值返回,类似Python
  • 返回值也可以在函数声明的时候定义名字,return的时候不需要指定return的变量即可
@H_301_36@func ReadFull(r Reader,buf []byte) (n int,err error) { for len(buf) > 0 && err == nil { var nr int nr,err = r.Read(buf) n += nr buf = buf[nr:] } return }
  • defer只能延迟函数,并且函数调用的实参会在遇到defer语句的时候就被执行,同时多个defer是类似栈式执行的,后来的先执行

数据

数据有两种分配方式newmake

  • new是用来分配内存的内建函数,但它不会初始化内存,只会将内存置零。new(T)返回一个指针, 该指针指向新分配的,类型为T的零值。
  • 内建函数make(T,args)的目的不同于new(T)。它只用于创建切片、映射和信道,并返回类型为T(而非*T)的一个已初始化 (而非置零)的值

切片

  • 切片保存了对底层数组的引用,若你将某个切片赋予另一个切片,它们会引用同一个数组。 若某个函数将一个切片作为参数传入,则它对该切片元素的修改调用者而言同样可见, 这可以理解为传递了底层数组的指针。

映射

  • map映射与切片一样也是引用类型,将映射传入函数中,并更改了该映射的内容,则此修改调用者同样可见
  • 映射的键存在时第二个返回值会返回true,不存在时返回falseseconds,ok := timeZone[tz]
  • delete(timeZone,"PDT"),要删除映射中的某项,可使用内建函数 delete,它以映射及要被删除的键为实参。 即便对应的键不在该映射中,此操作也是安全的。

print

  • fmt.Println可以直接使用变量当参数,打印变量的值
  • fmt.Printf类似C语言的打印方式

append

  • append函数的定义如这样
@H_301_36@func append(slice []T,elements ...T) []T
  • append 会在切片末尾追加元素并返回结果
@H_301_36@x := []int{1,2,3} x = append(x, 4, 5, 6)
  • 将一个切片追加到另一个切片中
@H_301_36@x := []int{1,2,3} y := []int{4,5,6} x = append(x,y...)

常量

  • Go 中的常量就是不变量。它们在编译时创建,定义它们的表达式必须也是可被编译器求值的常量表达式。
  • 枚举常量使用枚举器 iota 创建。由于 iota 可为表达式的一部分,而表达式可以被隐式地重复,这样也就更容易构建复杂的值的集合了
@H_301_36@const ( // 通过赋予空白标识符来忽略第一个值 _ = iota // ignore first value by assigning to blank identifier KB ByteSize = 1 << (10 * iota) MB GB TB PB EB ZB YB )

变量

  • 变量的初始化与常量类似,但其初始值也可以是在运行时才被计算的一般表达式。

init

  • 每个源文件都可以通过定义自己的无参数 init 函数来设置一些必要的状态。init 函数还常被用在程序真正开始执行前,检验或校正程序的状态。

方法

  • 若该值是可寻址的, 那么该语言就会自动插入取址操作符来对付一般的通过值调用的指针方法。在我们的例子中,变量 b 是可寻址的,因此我们只需通过 b.Write 来调用它的 Write 方法,编译器会将它重写为 (&b).Write。
  • 可寻址的意思就是在内存中或者寄存器中能找到。出于方便不管是值还是指针类型的都可以调用指针类型的方法,并且最好所有方法都写成指针类型的方法
@H_301_36@func (p *ByteSlice) Write(data []byte) (n int,err error) { slice := *p *p = slice return len(data),nil }

接口

  • 接口是一个包含了很多方法的集合,只要某个类型实现了这些方法,就可以使用这个接口,这个接口的类型就可以变成这个类型。
@H_301_36@type Abser interface { Abs() float64 } func main() { var a Abser f := MyFloat(-math.Sqrt2) a = f // a MyFloat implements Abser fmt.Println(a.Abs()) } type MyFloat float64 func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) }
  • 可以判断一个接口是否可以变换为某个类型。若类型断言失败,str 将继续存在且为字符串类型,但它将拥有零值,即空字符串
@H_301_36@str,ok := value.(string)
  • 接口只是方法的集合,而几乎任何类型都能定义方法

空白标识符

  • 导入某个包或声明某个变量而不使用它就会产生错误。未使用的包会让程序膨胀并拖慢编译速度, 而已初始化但未使用的变量不仅会浪费计算能力,还有可能暗藏着更大的 Bug。 然而在程序开发过程中,经常会产生未使用的导入和变量。虽然以后会用到它们, 但为了完成编译又不得不删除它们才行。空白标识符就能提供一个临时解决方案。
@H_301_36@import ( "fmt" "io" "log" "os" ) var _ = fmt.Printf // For debugging; delete when done. // 用于调试,结束时删除 var _ io.Reader // For debugging; delete when done. // 用于调试,结束时删除 func main() { fd,err := os.Open("test.go") if err != nil { log.Fatal(err) } // TODO: use fd. _ = fd }

goroutine

  • 我们称之为 goroutine ,是因为现有的术语—线程、协程、进程等等—无法准确传达它的含义。 Goroutine 具有简单的模型:它是与其它 goroutine 并发运行在同一地址空间的函数。它是轻量级的, 所有消耗几乎就只有栈空间的分配。而且栈最开始是非常小的,所以它们很廉价, 仅在需要时才会随着堆空间的分配(和释放)而变化。
  • Goroutine 在多线程操作系统上可实现多路复用,因此若一个线程阻塞,比如说等待 I/O, 那么其它的线程就会运行。Goroutine 的设计隐藏了线程创建和管理的诸多复杂性。

channel

  • 信道与映射一样,也需要通过 make 来分配内存。其结果值充当了对底层数据结构的引用。 若提供了一个可选的整数形参,它就会为该信道设置缓冲区大小。默认值是零,表示不带缓冲的或同步的信道。
  • 无缓冲信道在通信时会同步交换数据,它能确保(两个 goroutine)计算处于确定状态
  • 带缓冲的信道可被用作信号量,例如限制吞吐量。

猜你在找的Go相关文章