go语言的基础语法(变量、常量、基本数据类型,for、switch,case、数组、slice(切片)、make和new、map)

本文介绍了Go语言的基础知识,包括变量的声明、批量声明、类型推导和简短声明,以及常量的声明和使用。详细讲解了Go语言的基本数据类型,如整型、浮点型、布尔型、字符串等,并探讨了数组、切片、结构体等复合类型。此外,还涵盖了控制结构,如if、for、switch的用法,以及如何通过for range遍历数组和切片。最后,提到了指针、切片、map等高级概念,展示了它们的初始化、操作和遍历方式。
摘要由CSDN通过智能技术生成

1.Go语言中的变量

变量必须先声明再使用。
go语言中使用var来声明变量

变量声明
//变量声明
var name string
var age int
批量声明
//批量声明
var (
	nameFirst string
	score int
	flag bool
)
类型推导、简短变量声明:
func main() {

	name = "xiaoming"
	flag = false
	fmt.Printf("name:%s",name)
	//类型推导(根据变量判断事什么类型)
	var name2 = "哈哈哈"
	fmt.Printf(name2)
	//简短变量声明,效果同var
	name3 := "xixixi"
}
匿名变量

多返回值时,不想接收某个值,用_标识

func main() {

	res, _:= count.Chen(1, 2)
	fmt.Print(res)

}

**补充:**go语言中非全局变量,var以后不使用编译不通过。为了节省空间。

2.Go语言中的常量

const
//变量声明
const  pi = 3.1415

const (
	name = "中国"
	age = "5000+"
	//不赋值,默认跟上一行保持一致
	age2
)

常量不可以被修改

iota

//类似枚举
const (
	//默认0
	b1 = iota
	b2
	b3
	_
	b4
)

func main() {
	fmt.Println(b1,b2,b3,b4)
}

consts中每多一次变量声明。iota就会+1

const (
	//加一行变量生成iota才会+1
	b1  ,b2 = iota+1,iota+2
	b3, b4 = iota+1,iota+2
)

func main() {
	fmt.Println(b1,b2,b3,b4)
}

3.Go语言中的基本数据类型

Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道(channel)等。

基本数据类型

整型: 分为以下两个大类: 按长度分为:int8、int16、int32、int64 对应的无符号整型:uint8、uint16、uint32、uint64
其中,uint8就是我们熟知的byte型,int16对应C语言中的short型,int64对应C语言中的long型。

类型 描述
uint8 无符号 8位整型 (0 到 255)
uint16 无符号 16位整型 (0 到 65535)
uint32 无符号 32位整型 (0 到 4294967295)
uint64 无符号 64位整型 (0 到 18446744073709551615)
int8 有符号 8位整型 (-128 到 127)
int16 有符号 16位整型 (-32768 到 32767)
int32 有符号 32位整型 (-2147483648 到 2147483647)
int64 有符号 64位整型 (-9223372036854775808 到 9223372036854775807)

uint 32位操作系统上就是uint32,64位操作系统上就是uint64
int 32位操作系统上就是int32,64位操作系统上就是int64
uintptr 无符号整型,用于存放一个指针

浮点型数:float32和float64。这两种浮点型数据格式遵循IEEE 754标准: float32 的浮点数的最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32。可以使用一个常量定义:math.MaxFloat64。

打印浮点数时,可以使用fmt包配合动词%f,代码如下:

package main
import (
        "fmt"
        "math"
)
func main() {
        fmt.Printf("%f\n", math.Pi)
        fmt.Printf("%.2f\n", math.Pi)
}

复数:complex64和complex128。

布尔值:bool类型进行声明布尔型数据,true或false。

字符串:string类型声明,内部实现使用UTF-8编码。
字符串转义符:

字符含义
\r回车符(返回行首)
\t制表符
单引号
"双引号
\反斜杠

byte和rune类型:组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:

var a = 'a'
var b = 'b'

Go 语言的字符有以下两种:

uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
rune类型,代表一个 UTF-8字符。

if、for、switch

if

eg:

func getLevel() {
	score := 60
	if score >= 90 {
		fmt.Println("A")
	} else if score > 75 {
		fmt.Println("B")
	} else {
		fmt.Println("C")
	}
}
for(循环结构)

第一种写法:初始值,范围,i++

func forDemo() {
	for i := 0; i < 10; i++ {
		fmt.Println(i)
	}
}

第二种写法:初始化先写,后用 ;代替

func forDemo2() {
	i := 0
	for ; i < 10; i++ {
		fmt.Println(i)
	}
}

第三种写法:初始值和结束值都可以省略,因为i++放在for里面了

func forDemo3() {
	i := 0
	for i < 10 {
		fmt.Println(i)
		i++
	}
}
for range(键值循环)
		forrange结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用。forrange可以迭代任何一个集合(包括数组和map)。语法上很类似其它语言中foreach语句,但依旧可以获得每次迭代所对应的索引。

数组、切片、字符串返回索引和值。

	for key, value := range []int{1, 2, 3, 4} {
		fmt.Printf("key:%d  value:%d \n", key, value)
	}
	s := "hello中国"
	for i,v := range  s{
		fmt.Printf("%d: %c \n",i,v)
	}

map返回键和值。

	m := map[string]int{"hello": 100, "world": 200}
	for key, value := range m {
		fmt.Println(key, value)
	}

** 通道(channel)只返回通道内的值。**:

switch

使用switch语句可方便地对大量的值进行条件判断。

func switchDemo() {
	init:= 3
	switch init{
	case 1:
		fmt.Println("中午")
	case 2:
		fmt.Println("晚上")
	case 3:
		fmt.Println("早上")
	default:
		fmt.Println("输入错误!")
	}
}

其中,case可能有多个参数:

func testSwitch3() {
	switch n := 3; n {
	case 1, 3, 5, 7, 9:
		fmt.Println("奇数")
	case 2, 4, 6, 8:
		fmt.Println("偶数")
	default:
		fmt.Println(n)
	}
}

分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。例如:

func switchDemo() {
	age := 10
	switch {
	case age < 10:
		fmt.Println("小学生")
	case age > 10 && age <= 18:
		fmt.Println("年轻人")
	case age > 18:
		fmt.Println("成年了")
	default:
		fmt.Println("这岁数不对啊")
	}
}
goto(跳转到指定标签)

要退出双层for循环很麻烦,这时候可以用goto

func gotoDemo() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// 设置退出标签
				goto breakFlag
			}
			fmt.Printf("%d-%d \n", i, j)
		}
	}
	return
	// 标签
breakFlag:
	fmt.Println("结束for循环")
}

数组

Array(数组):

定义

必须指定数组的长度

// 定义一个长度为5元素类型为int的数组a
var a [5]int
var b [5]bool

补充:数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1,访问越界(下标在合法范围之外),则触发访问越界,会panic。

数组的初始化

1。初始化的时候就赋值

func main() {
	var testArray [3]int                        //数组会初始化为int类型的零值
	var numArray = [3]int{1, 2}                 //使用指定的初始值完成初始化
	var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
	fmt.Println(testArray)                      //[0 0 0]
	fmt.Println(numArray)                       //[1 2 0]
	fmt.Println(cityArray)                      //[北京 上海 深圳]
}

2.可以不指定数组的长度,自行推断

func main() {
	var testArray [3]int
	var numArray = [...]int{1, 2}
	var cityArray = [...]string{"北京", "上海", "深圳"}
	fmt.Println(testArray)                          //[0 0 0]
	fmt.Println(numArray)                           //[1 2]
	fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
	fmt.Println(cityArray)                          //[北京 上海 深圳]
	fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}
数组的遍历

数组遍历两种方法,一种for循环,一种用for range

func main() {
	var a = [...]string{"北京", "上海", "深圳"}
	// 方法1:for循环遍历
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i])
	}

	// 方法2:for range遍历
	for index, value := range a {
		fmt.Println(index, value)
	}
}

多维数组

二位数组的定义:

func main() {
	a := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	fmt.Println(a) //[[北京 上海] [广州 深圳] [成都 重庆]]
	fmt.Println(a[2][1]) //支持索引取值:重庆
}

二维数组的遍历:

func main() {
	a := [3][2]string{
		{"北京", "上海"},
		{"广州", "深圳"},
		{"成都", "重庆"},
	}
	for _, v1 := range a {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}
}

切片(slice)

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。

声明
	var name []int
	fmt.Print(name)
切片表达式

切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。 切片表达式中的low和high表示一个索引范围(左包含,右不包含),也就是下面代码中从数组a中选出1<=索引值<4的元素组成切片s,得到的切片长度=high-low,容量等于得到的切片的底层数组的容量。

	a := [5]int{1, 2, 3, 4, 5}
	// s := a[low:high],左包含右不包含
	s := a[1:3]
	//len(数组长度),cap(切片的长度):从指针指向的数组位置到最后一个位置才是容量
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
完整切片表达式

a[low : high : max]

	a := [5]int{1, 2, 3, 4, 5}
	t := a[1:3:5]
	fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}
使用make()函数构造切片

我们上面都是基于数组来创建的切片,如果需要动态的创建一个切片,我们就需要使用内置的make()函数,格式如下:

make([]T, size, cap)

	a := make([]int, 2, 10)
	fmt.Println(a)      //[0 0]
	fmt.Println(len(a)) //2
	fmt.Println(cap(a)) //10
切片的本质

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。

切片的赋值拷贝

拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容.是引用类型,会直接修改内存变量

s1 := make([]int, 4) //[0 0 0]
	s2 := s1             //将s1直接赋值给s2,s1和s2共用一个底层数组
	s2[0] = 100
	fmt.Println(s1) //[100 0 0]
	fmt.Println(s2) //[100 0 0]
切片遍历
	s := []int{1, 7, 9}

	for i := 0; i < len(s); i++ {
		fmt.Println(i, s[i])
	}

	for index, value := range s {
		fmt.Println(index, value)
	}
append()方法为切片添加元素

函数append()可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加…)。

	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]

	//直接append
	var s3 []int
	s3 = append(s, 1, 2, 3)
切片的扩容策略

$GOROOT/src/runtime/slice.go源码:

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
	newcap = cap
} else {
	if old.len < 1024 {
		newcap = doublecap
	} else {
		// Check 0 < newcap to detect overflow
		// and prevent an infinite loop.
		for 0 < newcap && newcap < cap {
			newcap += newcap / 4
		}
		// Set newcap to the requested cap when
		// the newcap calculation overflowed.
		if newcap <= 0 {
			newcap = cap
		}
	}
}
使用copy()函数复制切片

使用直接赋值会导致两个数组的值都变成要修改的值,因为共享同一个内存地址。因此使用copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的使用格式如下:

copy(targetSlice, sourceSlice []T)

// copy()复制切片
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //使用copy()函数将切片a中的元素复制到切片c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
从切片中删除元素

官方没有指定的方法,这里的思路是将要删除的元素的前面的数据拼接上要删除后的数组,算是删除了元素。

// 从切片中删除元素
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	a = append(a[:0], a[3:]...)
	fmt.Println(a) //[ 33 34 35 36 37]
}

指针和make和new

指针

取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:

对变量进行取地址(&)操作,可以获得这个变量的指针变量。
指针变量的值是指针地址。
对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。

func main() {
	//指针取值
	a := 10
	b := &a // 取变量a的地址,将指针保存到b中
	fmt.Printf("type of b:%T\n", b)
	c := *b // 指针取值(根据指针去内存取值)
	fmt.Printf("type of c:%T\n", c)
	fmt.Printf("value of c:%v\n", c)
}
make和new

new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。

/*var a *int
*a = 100
fmt.Println(*a)*/
//上述代码会报错,因为a是指针但没有初始化,是nil
//应当初始化
	var a= new(int)
	fmt.Println(a)//0xc000088220
	fmt.Println(*a)//0,如果new的是string,这块的值是空字符串

make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
new与make的区别

二者都是用来做内存分配的。
make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针

b := make(map[string]string,10)
	b["哈哈哈"] = "笑一笑"
	b["呜呜呜"] = "哭了"
	for key, va := range b {
		fmt.Print(key+": ")
		fmt.Println(va)
	}
	//呜呜呜: 哭了
	//哈哈哈: 笑一笑

map

Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现,map是引用类型,必须初始化才能使用。

初始化map并添加值并遍历
	var a = make(map[string]int,1)//虽然会自动扩容,但是最高估算好容量
	a["hahah"] = 1
	a["bbb"] = 2

	for key, va := range a {
		fmt.Print(key+": ")
		fmt.Println(va)
	}

	b := make(map[string]string,10)
	b["哈哈哈"] = "笑一笑"
	b["呜呜呜"] = "哭了"
	for key, va := range b {
		fmt.Print(key+": ")
		fmt.Println(va)
	}
	//查看是否有key
	va,er := b["ddd"]
	if !er {
		fmt.Println("没有这个key:"+va)
	}

初始化直接赋值
a:= map[string]string{
		"name": "go",
		"pa": "123456",
	}
delete()函数删除键值对

使用delete()内建函数从map中删除一组键值对

b := make(map[string]string,10)
	b["哈哈哈"] = "笑一笑"
	b["呜呜呜"] = "哭了"

	delete(b,"哈哈哈")

	for key, va := range b {
		fmt.Print(key+": ")
		fmt.Println(va)
	}
	//呜呜呜: 哭了
按照指定顺序遍历map

没有符合的函数,只能先对key进行排序,之后再输出

sortMap :=make(map[string]int,200)
	for i := 1000; i > 0; i-- {
		 //生成数
		sortMap["stu"+strconv.Itoa(i)] = i
	}
	keys := make([]string,0,200)
	for key := range sortMap {
		keys = append(keys,key)
	}

	sort.Strings(keys)
	fmt.Println(sortMap)
	for _, key := range keys {
		fmt.Println(sortMap[key])
	}
元素为map类型的切片

在切片中加入map元素

s := make([]map[int]string,0,10)
	//要初始化才能使用
	mapTemp :=	make(map[int]string,10)
	mapTemp[1] = "哈哈哈"
	mapTemp[2] ="xixixi"
	//添加元素
	s = append(s,mapTemp)
	//再次添加一个
	mapTemp2 :=	make(map[int]string,10)
	mapTemp2[1] = "哈哈哈2"
	mapTemp2[2] ="xixixi2"
	s = append(s,mapTemp2)
	fmt.Println(s)

结果://[map[1:哈哈哈 2:xixixi] map[1:哈哈哈2 2:xixixi2]]

值为切片类型的map
	s  :=make(map[string][]int,10)
	s["笑"] = []int{1,2,3}
	s["哭"] = []int{4,5,6}
	fmt.Println(s)
	fmt.Println(s["哭"])

结果:
map[哭:[4 5 6] 笑:[1 2 3]]
[4 5 6]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值