go基础(一)基础数据类型与控制结构

基础数据类型与变量

基本数据类型

go语言提供了丰富的数据类型

整形

byte,int,int8,int16,int32,int64,还有uint等

浮点

float32,float64

字符串

string

rune

rune等同于int32,这里提一个用法,统计非unicode字符数,用rune

类型转换

go不支持隐式类型转换,必须显示指定,类似函数,valueOfTypeB = typeB(valueOfTypeA), demo

a := 5.0
b := int(a)

变量

变量的定义相对灵活,go语言的一个特性是对变量类型的自动推导,看例子。

普通声明

普通声明使用var,变量名在前类型在后

    // var 声明
	var value1 int = 123
	// 或者
	var value2 int
	value2 = 123
自动推导类型

可以省略变量的类型,由go自动推导

	var value3 = 123
	fmt.Printf("value3 type %T\n", value3) // 推导为int
	var value4 = 3.14
	fmt.Printf("value4 type %T\n", value4) // 推导为float64
    var value5 = 's'
	fmt.Printf("value5 type %T\n", value5) // 推导为int32
	var value6 = "hello"
	fmt.Printf("value6 type %T\n", value6) // 推导为string
    var value7 = intValue() // intValue函数返回int值
	fmt.Printf("value7 type %T\n", value7) //推导为int
冒号简写

上面的类型推导可以采用冒号简写

    value8 := 234
    value9 := 3.14
    value10 := "string"
    value11 := intValue() 
多个变量同时定义
	var a1, b1, c1 int = 1, 2, 3
	var a2, b2, c2 = 4, 5, 6
	a3, b3, c3 := 7, 8, 9
集中声明

多个变量建议集中声明

	var (
		ivalue int
		fvalue float64
		svalue string
	)
	ivalue, fvalue, svalue = 234, 3.1415, "abc"
匿名变量

匿名变量用来对数据做丢弃处理,例如一个函数返回了两个值a和b,只需要a,如果同时声明了b没用到,编译会报错,这时候可以用匿名变量来代替b,即下划线_

	// 匿名变量
	first, second := intValue2()  // intValue2 有两个返回值
	_, value := intValue2()  // 丢弃第一个返回值不处理
	key, _ := intValue2() 	// 丢弃第二个返回值不处理

常量

常量采用const声明

	const STR string = "const"	// 指定类型
	const PI = 3.1415			// 自动推导类型
	const VALUE = 2333			// 自动推导类型
常量集中声明与iota
// iota 自增常量,从0开始
	// 集中声明
	const (
		a = iota // a=0
		b, c, d = iota, iota, iota // 1,1,1 换行才会自增
		e = iota // 2
	)
	const (  // 出现const则iota重置为0
		f = iota
		g  // 省略复制,go语言可自动复制,g=1
		_ // 跳过值,跳过2
		h // h = 3
	)

复合数据类型

复合数据类型有指针、数组、切片、map、通道、结构体、接口,这里涉及指针、数组、切片、map,其他的在后面

指针

go的指针与c的指针类似,*来声明指针,&来对指针赋值,取值则使用星号*

	value := 123
	var intp *int // *声明为指针类型
	intp = &value // *声明变量为指针类型,
	fmt.Println(*intp) // *取值

其他类型的指针会随 对应的类型说明

数组

数组是定长不可变的,长度在声明时需确定,声明方式有以下几种:

	var arr1 [3]int // 显示声明,指定长度,不指定元素值,默认值为0
	arr2 := [4]int{1,2,3} // 自动推导类型,指定长度,指定部分元素值,未指定的默认值为0
	arr3 := [...]int{1,2,3,4} // 自动推导类型,中括号的...表示不指定长度,由后面元素推导
	arr4 := [...]int{1:5, 4:6} // 自动推导类型,自动推导长度,1:5表示下标为1的元素值为5,未指定的默认值为0

	fmt.Println(len(arr4)) // len获取数组长度

	// 数组指针
	var arrPtr1 *[4]int = &arr2
	arrPtr2 := &arr4
	
	// 数组赋值
	arr1[1] = 6

数组的长度与遍历

主要有两种遍历,使用下标遍历和使用range函数遍历。
下标遍历需用len()获取数组长度

	// 数组遍历,下标遍历
	for i := 0; i < len(arr4); i ++ { // len获取长度
		fmt.Println(arr4[i])
	}

range()函数提供遍历功能,返回两个值,第一个为下标,第二个为位置上的值

	// range 遍历
	arr5 := [...]int{1,2,3,4}
	for idx, value := range(arr5)  {  // 返回两个值分别为下标和元素的值
		fmt.Println("idx ", idx, " value ", value)
	}
	for _, value := range(arr5)  {  // 不使用下标,可以用匿名变量替代
		fmt.Println(" value ", value)
	}

切片

数组长度是不可变的,于是就有了可变长度的切片。一个切片由数组、长度、容量三个元素组成

切片的声明

切片的声明有多种

从数组

从一个已经存在的数组声明切片

	arr := [4]int{1,2,3,4}
	
	sli1 := arr[0:4] // 从数组声明一个切片,[letf, right]表示切片的下标范围,包含left,不包含right
	sli2 := arr[2:] // 到数组末尾,可省略右边区间,等价于arr[2:4]
	sli3 := arr[:3] // 从数组第一个元素开始,可省略左边区间,等价于arr[0:4]
	sli4 := arr[:]  // 头尾均省略,等价于arr[0:4]
make函数

使用make函数创建切片。make有三个参数,第一个表示类型,第二个表示长度,第三个表示容量(可省略)

	sli5 := make([]int, 10)  // 参数中的[]int表示创建的类型,10表示切片长度,此时容量也是10
	sli6 := make([]int, 10, 15) // 15 表示数组的容量,容量大于等于长度

切片的操作

  • len()返回长度
  • cap()返回底层数组容量
  • append()追加元素
  • copy()复制切片
	fmt.Println(len(sli6))  // 长度
	fmt.Println(cap(sli6)) 	// 底层数组容量
	sli6 = append(sli6, 6)  // 在末尾追加

	sli8 := make([]int, 10, 15)
	copy(sli8, sli6)  // 从sli6拷贝到sli8
	fmt.Println(sli8)

map

声明

map的声明有两种,make和直接初始化

	var string2int map[string]int = make(map[string]int, 123) // make初始化map,123为容量,可省略
	string2int["abc"]=1  // 赋值
	int2string := map[int]string{}  // 直接声明并初始化为空
	int2string2 := map[int]string{1:"a", 2:"b"}  // 直接声明并用值初始化

map的操作

// 获取元素个数
	fmt.Println(len(int2string2))
	
	// 获取元素值
	var value string
	var exist bool
	value, exist = int2string[1] // 获取元素,返回两个字段,第一个为value值,第二个为是否存在
	if exist {
		fmt.Println(value)
	}
	fmt.Println(int2string[3])  // 对于不存在的元素,获取到的值为0值

	// range 遍历
	for key, value := range int2string2 {
		fmt.Println("key:", key, " value:", value)
	}
	
	// 删除map中的元素
	delete(int2string2, 1)

值传递介绍

对于函数中的变量传递,遵循以下原则:

  • 基本类型:值传递
  • 数组:值传递
  • slice:引用传递
  • map:引用传递

下面举例说明

func main() {

	iValue := 123
	intChange(iValue) // 修改iValue的值
	fmt.Println(iValue) // 输出123,值未改变

	array := [3]int{1,2,3}
	arrayChange(array)
	fmt.Println(array) // {1,2,3}值未改变

	sli := []int{1,2,3}
	sliceChange(sli)
	fmt.Println(sli) // {2,2,3}值改变

	int2int := map[int]int{} // 空map
	mapChange(int2int)
	fmt.Println(int2int) // 有值
}

func intChange(value int) {
	// value的值是拷贝得来
	value = value + 1
}

func arrayChange(arr [3]int) {
	arr[0] = arr[0] + 1
	arr[1] = arr[1] + 1
	arr[2] = arr[2] + 1
}

func sliceChange(sli []int) {
	sli[0] = sli[0] + 1
}

func mapChange(m map[int]int) {
	m[0] = 123
}

如果想通过函数来改变基本类型和数组的值,需要用指针来操作

func changeValueByPointer() {
	iValue2 := 100
	intChangeByPonter(&iValue2)
	fmt.Println(iValue2)  // 101 值改变

	array1 := [3]int{1,2,3}
	arrayChangeByPointer(&array1)
	fmt.Println(array1) // {2,2,3} 值改变
}

func intChangeByPonter(valuep *int) {
	*valuep = *valuep + 1
}

func arrayChangeByPointer(arrp *[3]int) {
	(*arrp)[0] = (*arrp)[0] + 1
}

控制结构

控制结构包含三部分内容

  • if 条件判断
  • switch 条件选择
  • for 循环

if 条件判断

与c、java等语言不同,go语言的if语句不需要用小括号包起来,且if与条件之间需要有空格、if与{要在同一行、条件与{之间需要有空格。

	a := 10
	if a > 0 {
		fmt.Println(a)
	}

更近一步,在if和判断语句之间,可以有一个初始化的语句,与判断语句用逗号分隔:

func main() {
	
	if b := 10; b > 0 {  // 初始化局部变量b
		fmt.Println(b)   // b的作用域在if整个语句内
	}

	if c := getValue(); c > 0 {  // 调用函数初始化
		fmt.Println(c)
	}
}

func getValue() int {
	return 10
}

但在实际使用中,建议将值的初始化和条件分开。

多个条件判断,同样是用if-else来实现

func ifElseDemo() {
	if value := getValue(); value == 0 {
		fmt.Println("value == 0")
	} else if value > 0 {   // value的作用域是整个if语句,这里仍然可以访问
		fmt.Println("value > 0")
	} else {
		fmt.Println("value < 0")
	}
}

注意:即使条件成立需要执行的语句只有一行,也需要用大括号包裹起来,不能省略。这是其他语言建议的格式,go语言强制这样做

switch 条件选择

go的switch有以下特点:

  • switch 后面可以跟任何类型的值匹配,不限于整数
  • 同时switch后面可以跟一个简单的初始化语句,类似if。
  • 每个case语句结束后,不需要使用break
  • 新增fallthrough关键字,可以跳过下一条的语句判断,直接执行语句
func switchDemo() {
	rand.Seed(time.Now().Unix())
	a := rand.Intn(5)
	fmt.Println(a)
	switch a {
	case 0, 1 :
		fmt.Println("a in (0, 1)")
		fallthrough  // 不会判断 case 2, 3 是否满足,直接执行 fmt.Println("a in (2, 3)")
	case 2, 3 :
		fmt.Println("a in (2, 3)")
	case 4 :
		fmt.Println("a = 4")
	}
}

for循环

go中的循环只有for关键字,没有while和都-while关键字,但是可以实现相同的功能

while (true)

使用for不加条件来实现while (true)功能

	i := 1
	for {
		fmt.Println(i)
		if i > 10 {
			break
		}
		i++
	}

while (condition)

使用 for condition 来实现

	j := 0
	for j > 10 {  // 判断条件挪到这里
		fmt.Println(j)
		j++
	}

其他语言的for结构

即 for init; condition; post 来执行循环

	for k := 0; k < 10; k++ {
		fmt.Println(k)
	}

range 遍历

range遍历用来访问map、数组、切片等

	int2int := make(map[int]int)
	for key, value := range int2int {  // map遍历
		fmt.Println(key, value)
	}

	intSli := make([]int, 10, 10)
	for index, value := range intSli {
		fmt.Println(index, value)
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值