一、常量:
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const (
size int64 = 1024
eof = -1 // 无类型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo"
二、Go语言预定义了这些常量:【true】、【false】和【iota】。
iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。
从以下的例子可以基本理解iota的用法:
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
三、枚举:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 这个常量没有导出, 因为他是小写开头, 仅包内可见
)
四、整型: 既然整型有平台相关性, 还是少用int uint好一些。
类 型 长度(字节) 值 范 围
int8 1 ?128 ~ 127
uint8(即byte) 1 0 ~ 255
int16 2 ?32 768 ~ 32 767
uint16 2 0 ~ 65 535
int32 4 ?2 147 483 648 ~ 2 147 483 647
uint32 4 0 ~ 4 294 967 295
int64 8 ?9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
uint64 8 0 ~ 18 446 744 073 709 551 615
int 平台相关 平台相关
uint 平台相关 平台相关
uintptr 同指针 在32位平台下为4字节,64位平台下为8字节
五、浮点型:
Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,float64等价于C语言的double类型。
在Go语言里,定义一个浮点数变量的代码如下:
var fvalue1 float32
fvalue1 = 12
fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型
浮点数比较:
因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。下面是一种推荐的替代方案:
import "math"
// p为用户自定义的比较精度,比如0.00001
func IsEqual(f1, f2, p float64) bool {
return math.Fdim(f1, f2) < p
}
六、【字符串】
声明: var str string
str = “hello”
或者: str := “hello”
操作: ch := str[0] // 取字符串的第一个字符
字符串的内容不能在初始化后被修改: str[0] = 'X' // 编译错误
x + y 字符串连接 "Hello" + "123" // 结果为Hello123
len(s) 字符串长度 len("Hello") // 结果为5
s[i] 取字符 "Hello" [1] // 结果为'e'
更多的字符串操作,golang标准库strings包。
七、数组:
声明:以下为一些常规的数组声明方法:
[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 } // 复杂类型数组
[1000]*float64 // 指针数组
[3][5]int // 二维数组
[2][2][2]float64 // 等同于[2]([2]([2]float64))
循环:
for i := 0; i < len(array); i++ {
fmt.Println("Element", i, "of array is", array[i])
}
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
【★ 值类型】所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。
需要特别注意的是,在Go语言中数组是一个值类型(value type)。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所
传入数组的一个副本。
八、数组切片(slice)
声明:
基于数组创建一个数组切片 var mySlice []int = myArray[:5]
基于myArray的所有元素创建数组切片: mySlice = myArray[:]
创建一个初始元素个数为5的数组切片,元素初始值为0: mySlice1 := make([]int, 5)
创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:mySlice2 := make([]int, 5, 10)
直接创建并初始化包含5个元素的数组切片: mySlice3 := []int{1, 2, 3, 4, 5}
数组切片支持Go语言内置的cap()函数和len()函数,代码清单2-2简单示范了这两个内置函数的用法。
可以看出,cap()函数返回的是数组切片分配的空间大小,而len()函数返回的是数组切片中当前所存储的元素个数。
添加元素:
mySlice = append(mySlice, 1, 2, 3)
mySlice2 := []int{8, 9, 10}
// 给mySlice后面添加另一个数组切片
mySlice = append(mySlice, mySlice2...) 。注意需要三个点...
复制数组切片:slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
【引用传递】 数组切片是引用传递。
九、map
声明:var personDB map[string] PersonInfo
personDB = make(map[string] PersonInfo)
// 往这个map里插入几条数据
personDB["12345"] = PersonInfo{"12345", "Tom", "Room 203,..."}
personDB["1"] = PersonInfo{"1", "Jack", "Room 101,..."}
// 从这个map查找键为"1234"的信息
person, ok := personDB["1234"]
// ok是一个返回的bool型,返回true表示找到了对应的数据
if ok {
fmt.Println("Found person", person.Name, "with ID 1234.")
} else {
fmt.Println("Did not find person with ID 1234.")
}
创建了一个初始存储能力为100的map: myMap = make(map[string] PersonInfo, 100)
赋值 : myMap["1234"] = PersonInfo{"1", "Jack", "Room 101,..."}
删除 : delete(myMap, "1234")
查找 : value, ok := myMap["1234"]
if ok { // 找到了
// 处理找到的value
}
【引用传递】 map是引用传递。
【★★★ 引用语义】 golang中的引用语义类型有: 数组切片、map、channel、interface。
struct(类)对象往往通过new创建出来,这时会是一个引用传递,new出来的本身就是一个指针。
直接声明struct得到的变量传递时是按值传递。★★★★★
十、 结构体struct
定义新类型: type Integer int : 定义个Integer 类型, 与int相同。
type Header map[string][]string
结构体:
type Rect struct {
x, y float64
width, height float64
}
func (r *Rect) Area() float64 {
return r.width * r.height
}
实例化对象:
rect1 := new(Rect)
rect2 := &Rect{}
rect3 := &Rect{0, 0, 100, 200}
rect4 := &Rect{width: 100, height: 200}
也可以rect5 := Rect{}.
加&符号和new的是指针对象,没有的则是值对象,这点和php、java不一致,在传递对象的时候要根据实际情况来决定是要传递指针还是值。
现在看还是用引用声明方式好一点。
构造函数: 查看官方文档,golang并没有构造函数一说。如果一定要在初始化对象的时候进行一些工作的话,可以自行封装产生实例的方法。
func NewPoem(param string, p ...interface{}) *Poem
示例:
func NewPoem(author string) (poem *Poem) {
poem = &Poem{}
poem.Author = author
return
}
struct是组合。
【TIPS】: 传统的继承,有两方面的作用: 一是复用,即子类复用父类的一部分方法,自己再添加一些特殊的。 二是表示,即父类提供
一个通用的表示方式,不同的子类去实现,这种也很常见比如抽象类。
那么第一种应该完全的切换到组合的思考方式, 而第二种则通过interface实现。 java已经没有了virtual关键字,引入了interface,go也保留了
interface,解决了第二个问题。 第一个go直接通过组合实现。
十一、 接口 interface
在Go语言出现之前,接口主要作为不同组件之间的契约存在。对契约的实现是强制的,你必须声明你的确实现了该接口。
为了实现一个接口,你需要从该接口继承。
在Go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口。 就可以赋值给这个接口。
【接口赋值】: var b LessAdder = &a ... (1) var b LessAdder = a ... (2) 应该用1的写法, 2会有问题。
【接口查询】:
var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
...
}
这个if语句检查file1接口指向的对象实例是否实现了two.IStream接口,如果实现了,则执行特定的代码。
在Go语言中,你可以询问接口它指向的对象是否是某个类型,比如:
var file1 Writer = ...
if file6, ok := file1.(*File); ok {
...
}
这个if语句判断file1接口指向的对象实例是否是*File类型,如果是则执行特定代码。
【类型查询】:
var v1 interface{} = ...
switch v := v1.(type) {
case int: // 现在v的类型是int
case string: // 现在v的类型是string
...
}
接口可以给接口赋值。 接口是引用传递。
-------------------------------------------
var i itest |
sp := new(stest) |
i = sp
fmt.Println("point i", unsafe.Sizeof(i)) |
fmt.Println("point s", unsafe.Sizeof(sp)) |
i.do() |
ss := stest{}
i = ss |
fmt.Println("struct i", unsafe.Sizeof(i)) |
fmt.Println("struct s", unsafe.Sizeof(ss)) |
输出:
point i 8 |
point s 4 |
struct i 8
struct s 40
可见: 接口类型永远大小是8,不管赋值给他的是new出来的指针还是结构体,都是可以的。 |结构体的指针大小是4。
-------------------------------------------
十二、 channel :
声明:var chanName chan ElementType。 如var ch chan int 或者,我们声明一个map,元素是bool型的channel:var m map[string] chan bool
定义:定义一个channel也很简单,直接使用内置的函数make()即可: ch := make(chan int)
要创建一个带缓冲的channel,其实也非常容易: c := make(chan int, 1024)
在调用make()时将缓冲区大小作为第二个参数传入即可,比如上面这个例子就创建了一个大小为1024的int类型channel,
即使没有读取方,写入方也可以一直往channel里写入,在缓冲区被填完之前都不会阻塞。
单向channel:
var ch1 chan int // ch1是一个正常的channel,不是单向的
var ch2 chan<- float64// ch2是单向channel,只用于写float64数据
var ch3 <-chan int // ch3是单向channel,只用于读取int数据
应该比较适合用于函数参数中。
关闭: close(ch)。
x, ok := <-ch 这个用法与map中的按键获取value的过程比较类似,只需要看第二个bool返回值即可,如果返回值是false则表示ch已经被关闭。
【引用传递】 channel是引用传递。
有疑问加站长微信联系(非本文作者)