Golang----语法

标准库文档

地址

变量声明

//全局变量
var nameTest1 string
var nameTest2 int
var nameTest3 bool
//批量声明,常用
var (
	name2 string
	age   int
	ok    bool
)
func test(){
	//局部变量,局部变量声明必须使用!
	var nameTest4="hello"//类型推导
	nameTest5 := "world"//简短声明,常用
}

数组定义

数组的长度是数组类型的一部分,确定即不可更改

	var array1 [3]bool
	array2 := [...]bool{0,1,2,3}//根据初始化自动推断数组长度
	array3 := [5]bool{0:1,4:3}//根据索引初始化

多维数组

	var array1 [3][4]bool
	array1 = [3][4]bool{
		[4]bool{true, false, true},
		[4]bool{true, false, true},
		[4]bool{true, false, true},
	}

iota常量计数器

iota 在const关键字出现时将被重置为0。const中每新增一行常声明,将使iota计数一次(iota可理解为const语句块中的行索引),使用iota能简化定义,在定义枚举时很有用。

package main

import "fmt"

const (
	_  = iota
	kb = 1 << (10 * iota)
	mb = 1 << (10 * iota)
	gb = 1 << (10 * iota)
	tb = 1 << (10 * iota)
	pb = 1 << (10 * iota)
)

func main() {
	fmt.Printf("hello Jc!\n")
	fmt.Printf("kb is %v\n", kb)
	fmt.Printf("mb is %d\n", mb)
	fmt.Printf("gb is %d\n", gb)
	fmt.Printf("tb is %d\n", tb)
	fmt.Printf("pb is %d\n", pb)
}

标准库fmt

格式化输入

	var (
		string1 string
		number1 int
		boo1    bool
	)
	fmt.Scan(&string1)
	fmt.Println(string1)

	fmt.Scanf("%s %d", &string1, &number1)
	fmt.Printf("%s %d\n", string1, number1)

	fmt.Scanln(&string1, &number1, &boo1)
	fmt.Println(string1, number1, boo1)

格式化输出 打印格式

占位符

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

字符串

``用于多行文字保持格式输出,可以用于路径原样输出

	string1 := `
多行文字
		测试	
	`
	string2 := `D:\Example Code\Go Demo\src\gitee.com\jcgogo`
	
	fmt.Println(string1)
	fmt.Println(len(string2))//打印字符串长度

字符串拼接

将两段字符串拼接

	string3 := fmt.Sprintf("%s,%s", string1, string2)

字符串分割

将字符串按\分割为列表

	result := strings.Split(string3, "\\")
	fmt.Println(result)

字符串包含内容判断

判断字符串中是否包含测试

	result2 := strings.Contains(string3, "测试")
	fmt.Println(result2)

前后缀判断

判断字符串前缀是否为D,后缀是否为o

	fmt.Println(strings.HasPrefix(string2, "D"))
	fmt.Println(strings.HasSuffix(string2, "o"))

字符串子串位置

字符c的第一个位置和最后一个位置

	fmt.Println(strings.Index(string2,"c"))
	fmt.Println(strings.LastIndex(string2,"c"))

字符串拼接

将分割好字符串的列表的以~~拼接

	fmt.Println(strings.Join(result1, "~~"))

for遍历对象

	for _, v := range string2 {
		fmt.Printf("%c ", v)
	}

切片(slice)

可变长数组

	var slice1 []int    //定义了一个int类型的切片(可变长数组)
	var slice2 []string //定义了一个string类型的切片

	// fmt.Print(slice1 == nil, slice2 == nil, "\n") //未使用赋值则未分配空间

	slice1 = []int{1, 2, 3}
	slice2 = []string{"jiejie", "Jc"}

	// fmt.Print(slice1, slice2)

	//长度和容量
	fmt.Printf("len(slice1):%d, cap(slice1):%d\n", len(slice1), cap(slice1))
	fmt.Printf("len(slice2):%d, cap(slice2):%d\n", len(slice2), cap(slice2))

	array1 := [...]int{1, 2, 3, 4, 5}
	slice3 := array1[0:3] //从数组中获取切片,左闭右开
	fmt.Printf("value:%d,type:%T\n", slice3, slice3)

	//切片的容量,是从切片的第一个位置开始,底层数组的容量,长度则为切片的长度
	fmt.Printf("len(slice3):%d, cap(slice3):%d\n", len(slice3), cap(slice3))

	slice3[0] = 99
	fmt.Printf("after change :array1:%d, slice3:%d\n", array1, slice3)
	for i, v := range slice3 {
		fmt.Println(i, v)
	}

切片的特性

切片的长度和容量,本质来说,切片有点c语言里指针的味道,底层数组指针,是引用类型,所以修改切片、或者修改被应用的数组,都会被穿透修改。

  • 对切片的修改会穿透到底层数组
  • 将切片赋值给其他变量,并对变量进行修改,也会穿透修改
  • 切片不能直接比较,除非与nil比较,因为切片为nil意味底层没有引用数组
  • 判断切片是否为空应使用len()
  • 切片的遍历是数组相同,可以用for range
    在这里插入图片描述

构造切片

	slice4 := make([]string, 5, 10) //make:type,len,cap
	fmt.Printf("data:%s,len:%d,cap:%d\n", slice4, len(slice4), cap(slice4))

切片扩容

  • 使用append()函数必须使用原来的变量接收

因为底层指向的数组,可能新建在了新的内存块上,指针需要重新指向地址。

	slice1 := make([]string, 2, 2)
	slice1 = []string{"Jc", "Jiejie"}
	fmt.Printf("len:%d,cap:%d\n", len(slice1), cap(slice1))
	fmt.Printf("before->data:%s,ptr:%p\n", slice1, &slice1)
	slice1 = append(slice1, "hello")
	fmt.Printf("len:%d,cap:%d\n", len(slice1), cap(slice1))
	fmt.Printf("after->data:%s,ptr:%p\n", slice1, &slice1)

	slice2 := []string{"小a", "小b", "小c"}
	slice1 = append(slice1, slice2...) //...将slice2拆分
	fmt.Printf("len:%d,cap:%d\n", len(slice1), cap(slice1))
	fmt.Printf("after->data:%s,ptr:%p\n", slice1, &slice1)

注意:使用...三个点,可以拆分切片

扩容规则

在这里插入图片描述

切片拷贝

要计算好存储对象的空间,否则会截断

	slice1 := []string{"Jc", "Jiejie"}

	slice2 := []string{"小a", "小b", "小c"}

	copy(slice1, slice2) //dst,src
	fmt.Printf("%s,%s\n", slice1, slice2)
	fmt.Printf("len:%d,cap:%d\n", len(slice1), cap(slice1))
	fmt.Printf("len:%d,cap:%d\n", len(slice2), cap(slice2))

切片切除元素

利用append,截断在append

	slice2 = append(slice2[:1], slice2[3:]...)
	fmt.Printf("%s\n", slice2)

指针

在这里插入图片描述

	var a int
	a = 3
	fmt.Printf("value:%d,addr:%p,type:%T\n", *(&a), &a, &a)

make 和 new

make也是用于内存分配的,区别于new,它只用于slice, map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。 make函数的函数签名如下:
在这里插入图片描述

make 和 new的区别

make 和 new的区别如图在这里插入图片描述

new:

	var pointer *int
	pointer = new(int)
	*pointer = 3
	fmt.Printf("%d\n", *pointer)

map

在这里插入=描述
需要先申请空间才能使用,map检测方法如下。

	var map1 map[string]string
	map1 = make(map[string]string, 1)
	map1["type"] = "test"

	fmt.Printf("%s\n", map1["type"])

	_, ok := map1["miss"]
	if !ok {
		fmt.Println("miss")
		//do something
	} else {
		//do something
	}

	for k, v := range map1 {
		fmt.Println(k, v)
	}

	//删除map成员
	delete(map1, "type")

map和slice的组合

	//声明一个切片,切片指向的类型为map的,key-string,value-string
	var slice1 = make([]map[string]string, 5, 5)
	slice1[0] = make(map[string]string, 2)
	slice1[0]["bot1"] = "test"
	slice1[0]["bot2"] = "test"
	fmt.Println(slice1[0])

	//声明一个map,map存放的类型为切片,key-string,value-slice(int)
	var map1 = make(map[string][]int, 5)
	map1["slice"] = []int{1, 2, 3}
	fmt.Println(map1)

单词出现次数

	string1 := "how do you do jc hh hh"
	result1 := strings.Split(string1, " ")
	stringmap := make(map[string]int, 5)

	for _, v := range result1 {
		//判断是否有key-v
		_, ok := stringmap[v]
		//若无,添加到map
		if !ok {
			stringmap[v] = 1
		} else { //若有,计数加1
			stringmap[v]++
		}
	}
	fmt.Println(stringmap)

函数

//函数定义,参数类型简写,缺省返回
func add(x, y, z int) (ret int) {
	ret = x + y
	return
}

//多个返回值
func multi() (int, string) {
	return 0, "ok"
}

//可变长参数,必须放在函数参数的最后
func dynValue(x int, y ...int) (ret int) {
	fmt.Println(x, y)
	return
}

func main() {
	j, k := multi()
	fmt.Println(j, k)
	dynValue(1, 2, 3)
}

defer

延时函数执行,在函数返回前再执行,(函数执行前会将用到的变量先压栈),return非原子操作,defer可能会修改到返回值。

func deferTest() {
	fmt.Println(1)
	defer fmt.Println(2)
	fmt.Println(3)
	fmt.Println(4)
}

func main() {
	deferTest()
}

函数作为参数(c语言函数指针)及 匿名函数

示例如下,无限套娃

func deferTest(a int) (string, int) {
	fmt.Println(1)
	return "", 1
}

//函数接受函数作为参数
func funcRecfunc(a func(int) (string, int)) {
	ret := a
	fmt.Printf("%T\n", ret)
}

//函数使用函数作为返回值
func funcReturnfunc() func(int) (string, int) {
	//匿名函数用法,一般放在函数内部
	ret := func(int) (string, int) {
		return "nil", 0
	}
	//匿名函数直接调用
	func(int) (string, int) {
		return "nil", 0
	}(1)
	return ret
}

//函数类型作为参数
func main() {
	a := deferTest
	fmt.Printf("%T\n", a)
	funcRecfunc(deferTest)
	fmt.Printf("%T\n", funcReturnfunc())
}

闭包

通常外部函数如果预留了接口来拓展其内部功能,那么要使用闭包实现。

//闭包,使得函数能使用外部作用域变量
func diliver(outside int) func(inside int) int {
	return func(inside int) int {
		inside += outside // 引用到了外层传入的参数
		return inside
	}
}

//实际应用,对外拓展内部功能。比方Jc写了一个函数eat,并预留了一个extern的函数接口
func eat(extern func()) {
	fmt.Println("Jc eat")
	extern()
}

//现在Jc学会了study,想边eat边study,但是study比较复杂,不满足extern接口要求
func study(studyWhat string) {
	fmt.Println("Jc eating and studying " + studyWhat)
}

//那么使用闭包可以解决
func combineEatStudy(study func(string)) func() {
	return func() {
		study("golang")
	}
}

func main() {
	// ret := diliver(5)
	// fmt.Printf("%d\n", ret(3))
	ret := combineEatStudy(study)
	eat(ret)
}

内置函数

new 和 make的区别

在这里插入图片描述

panic 和 recover

func a() {
	fmt.Println("A Func")
}
func c() {
	fmt.Println("C Func")
}
func b() {
	panic("B panic")
}

结构体和type

	//初始化方式1
	var person1 = person{
		name: "Jc",
		sex:  "boy",
	}
	//初始化方式2,获取到结构体的指针
	person4 := &person{
		"Jc",
		1,
		"boy",
	}

	person1.name = "Jc"
	person1.age = 18
	person1.sex = "boy"
	fmt.Println(person1.name, person1.age, person1.sex)
	fmt.Println(person4.name, person4.age, person4.sex)
	// 匿名结构体
	var person2 struct {
		name string
		age  int
		sex  string
	}
	fmt.Println(person2.name, person2.age, person2.sex)

	person3 := new(person)
	fmt.Println(person3.name, person3.age, person3.sex)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值