Go学习杂谈

使用Go已经快有半年了,为了适应新公司的开发需要,半道入行,写了很多基于Go的应用(当然大部分是二次开发),也算是Golang的小用户了。一直没有太多的时间很系统地去看一些Golang的书籍,平时写代码也是凭借着对Java/C++的经验去猜测写Golang的代码,对常用的一些系统库也是在工作中学习。今天也是想总结回顾一下之前在使用过程中学习了一些东西,也借此巩固分享一下。

先说说总体对Golang相对于其它面向对象语言的初步体会:

  1. 简单清晰,变量定义更简洁,吸收了javascript的语法,支持“动态类型”,没有java那么繁冗
  2. 突破常规
    为什么这么说呢,一般一说高级语言从语法上有比较大的相似性,比如C++, Java, 但Go感觉还是有比较大的反常规的语法:
  • 变量声明,包括参数,先声明变量名,再是变量类型
  • 方法签名支持返回参数命名
  • 类与接口类型

变量

声明与定义

Golang支持两种变量的声明方式:

  • 先声明,再定义: var var_name var_type
var name string
name = "John"
  • 用:=将声明跟定义放在一起
name := "John"
内置变量类型

Golang支持许多其它高级语言的build-in类型,比如int, long, float32, float64, 集合类型:map, array, slice

变量类型Example
mapscores := make(map[string]int)
arraycourses := []string {"math", "english"}
sliceslice1 := make([]int, length, capacity)or slice2 := array[i:len(array)]

关于slice与array在Golang里面的区别,推荐这一篇文章:Arrays vs Slices

简单总结它们的特点:

  1. array是fix-size,slice是可变长度的
  2. slice表示的是array某个**连续区间[start:end)**的值的列表
  3. slice结构不存储实际的变量值,实际的值都是存储在array上,可以把slice想像成一个sliceheader的结构,如下:
type sliceHeader struct {
    Length int,
    Capacity int,
    ZerothElement: *T
}

slice的capacity是其所指向array的长度,所以我们可以动态地增加slice的长度(slice2 := slice1[0:len(slice1)+1]),但这个长度必须小于它的capacity, 否则程序会报错。

自定义变量类型

Golang用struct来表示其它高级语言里面的类, 定义struct的语法:

type <struct_name> struct {
   Field1   field_type,
   ...
   FieldN   field_type
}

struct类型也可以实现field的继承,比如:

type TypeA struct {
   Field1 string
}

type TypeB struct {
   TypeA
   Field2  string
}

t := TypeB { TypeA{"field1_value"}, "field2_value"}
fmt.Println(t.Field1)  // "field1_value"
fmt.Print(t.Field2)    // "field2_value"

这样TypeB就有两个field:从TypeA继承过来的Field1以及自身定义的Field2
需要指出的是,Capitalize字母开头的field表示它是export的,这样在其它的包中也可以引用这个field, 如t.Field1,比如如果你struct需要marshal/unmarshar成json,就需要capitalize field name. 更多参考这里

指针类型

Go里面保留C/C++中的指针,但对指针类型变量与普通类型的变量,在使用上没有差异,比如:

type Student struct {
  Name string,
  class int,
  id    string
}

var studentA = Student{"John", 1, "20180004"}
fmt.Println(studentA.Name)

var pointerA *Student
pointA = &studentA
fmt.Println(pointA.Name)

当function的receiver参数的类型为指针时,意味着在function里面改变这个指针所指向的对象的值,则在调用方也可以看到这个变化,这个跟C++没有差别。
指针的引用也使得参数在模块,函数间的传递更具效率(跟传值比较)

空接口interface{}

interface{}在Go里面表示空接口类型,它可以表示任意具体的类型,这个有点像是Java里面的Object. 任何类型都实现了空接口。
比如fmt.Println(a …interface{})

常用的 function

len(): 获取array, slice或者map的长度

append(slice, item): 创建一个新的slice, 并将item追加到新slice的末尾,返回新的slice, 注意,只有返回的slice包含了新的item, 参数里面的slice并未追加。append也可以merge两个slice:

slice1 := []int{1, 2, 3}
slice2 := append(slice1, 4) // {1, 2, 3, 4}

// merge slice
slice3 := []int{4, 5, 6}
slice4 := append(slice1, slice3...) // [1, 2, 3, 4, 5, 6]

遍历集合

遍历数组可以有下面两种方式

slice := []int{1,2,3}
// #1 iterate both index and value
for i, v := range slice {
	fmt.Println(slice[i], "-", v)
}
// #2 iterate only index
for i := range slice {
	fmt.Println(slice[i])
}

map的遍历同样有下面类似的方式:

myMap := make(map[string]string)
myMap["key1"] = "v1"
myMap["key2"] = "v2"
	
for k := range myMap {
	fmt.Println(k)
}
for k, v := range myMap {
	fmt.Println(k + ":" + v)
}

三点运算符

…在Golang里面可以有几个意义

  • 在function的参数类型里面表示可变参数(variadic),而且只能是最后一个参数
// 在这里,names其实就是个slice, 等同于[]string
func Greetings(prefix string, names ...string) {
	for _, name := range names {
		fmt.Println(prefix, name)
	}
}

// hello, John
// hello, Jackie
// hello, May
  • 在调用包含可变参数里,…跟在slice后面表示展开(unpacking)这个slice
names := []string{"John", "Jackie", "May"}
Greetings("hello," names...) 
  • 定义数组时,表示数组的长度由初始化的值的列表长度决定
var names = [...]string{"John", "Jackie", "May"}
fmt.Printf("%T\n", names)  // [3]string
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值