go 学习笔记

go 学习笔记(三)


前言

接触了新的语言go,记录一下学习的笔记方便日后温故知新。

一、进制

1.二进制 0,1 满2进1
2.十进制 0-9 满10进1
3.八进制0-7 满8进1 数字0开头
4.十六进制0-9 A-F满16进1以0x 或者 0X开头 此处的 A-F不区分大小写

在golang中不能直接使用二进制来表示一个整数,他沿用了c的特点,可以用%b输出二进制

func main() {
	//二进制
	i := 5
	fmt.Printf("%b \n", i)

	//八进制
	j := 011
	fmt.Println(j)

	//十六进制
	k := 0x11
	fmt.Println(k)
}
从最低为开始(最右侧),每个位数上的数提取出来乘以进制数的(位数-1)次方,然后求和
二进制转十进制
	1011  从右到左四个数分别是 0 1 2 3 四个位
	计算
		1乘以20次幂 +
		1乘以21次幂 +
		0	+
		1乘以23次幂 = 11
八进制转十进制
	0123 转成十进制
	计算
		3*1 + 2*8的一次方 + 1*8的平方 = 83
十六进制转十进制
	0x34a
	a 是 10 +
	4 * 16 的一次幂 +
	3 * 16 的二次幂 = 842
十进制转二进制
	将该数不断除以2然后将每步得到的余数倒过来就是对应的二进制
		将56转成二进制
			65/228 余数 0
			28/214 余数 0
			14/27 余数 0
			7/23 余数 1
			3/21 余数 1 (商为1)
		最后得到 111000 = 56
十进制转八进制及十进制转十六进制方法参考十进制转二进制
二进制转八进制及十六进制
	二进制转八进制:将二进制的每三位一组(从低位开始组合),转成对应的八进制即可
		举例:11010101转成八进制
				11 010 101 二进制 10101011 分别等于十进制的 5 , 2 , 3 那么11010101转成八进制为325
二进制转十六进制
	将二进制的每四位一组(从低位开始组合),转成对应的十六进制即可
八进制十六进制转成二进制
	八进制转二进制:将八进制的每一位转成对应的一个3位的二进制数即可
		0237
			7:111
			7:011
			7:010:八进制的234转为二进制位10011111
十六进制转二进制:将十六进制的每一位转成对应的一个4位的二进制数即可

二、源码反码补码

1.对于有符号的而言

二进制的最高位是符号位,0表示正数,1表示负数
正数的原码反码补码都一样
负数的反码 = 源码符号位不,其他位取反(1 -> 0 , 0 -> 1)
负数的补码 = 它的反码 + 1
0 的反码,补码,都是0
在计算机运算的时候都是以补码的方式来运算的

2.位运算

&:两位全为1结果为否则为0
|:两位有一个为1结果为1否则为0
^:两位有一个为1,另一个为0结果为1否则为0

计算
	2&3:
		2的补码: 0000 0010
		3的补码: 0000 0011
		2&3: 0000 0010 转成 十进制的结果:2
	2|3:
		0000 0011 : 3
	2^3:
		0000 0001 : 1
   -2^2:
		-2的源码:1000 0010
		-2的反码:1111 1101
		-2的补码:1111 1110
		 2的补码:0000 0010
 -2^2的结果的补码:1111 1100
 -2^2的结果的反码:1111 1100 - 1 = 1111 1011
 -2^2的结果的源码:1111 1011 => 1000 0100 = -4

二进制加减:

二进制的运算算术运算二进制的加法:0+0=00+1=11+0=11+1=10(向高位进位);
二进制的减法:0-0=010-1=1(向高位借位) 1-0=11-1=0 (模二加运算或异或运算) ;
二进制的乘法:0 * 0 = 0 0 * 1 = 01 * 0 = 01 * 1 = 1 二进制的除法:0÷0 = 00÷1 = 01÷0 = 0 (无意义)1÷1 = 1 ;
逻辑运算二进制的或运算:遇11 二进制的与运算:遇00 二进制的非运算:各位取反。

三、流程控制

1.顺序
2.分支

//if
//	if
//	if else
//	if else if else ...
//		func main() {
//			if age := 1; age < 18 {
//				fmt.Println("小孩")
//			} else {
//				fmt.Println("大人")
//			}
//		}
//switch
	//golang中,case不需要加break即唯一匹配
		//1.case后面是一个表达式可是常量,变量,有返回值的函数
			func main() {
				var b byte = 'a'
				switch test(b) {
				case 'a':
					fmt.Println("hello a")
				case 'b':
					fmt.Println("hello b")
				default:
					fmt.Println("hello default")

				}
			}
			func test(b byte) byte {
				return b + 1
			}
		//2.switch和case的数据类型要保持一致
			func main() {
				n1 := 20
				n2 := 10
				switch n2 {
				case 1, add(n2), 22:
					fmt.Println("hello a")
				case n1:
					fmt.Println("hello b")
				default:
					fmt.Println("hello default")

				}
			}
			func add(i int) int {
				return i
			}
		//2.switch当初if else分支来使用
			func main() {
				n1 := 20
				switch {
				case n1 < 10:
					fmt.Println("hello")
				case n1 == 20:
					fmt.Println("hi")
				default:
					fmt.Println("how are you")
				}
			}

3.循环

for
	func main() {
		for i := 0; i < 5; i++ {
			fmt.Println("hello", i)
		}
	}
//遍历字符串注意事项:
	func main() {
		//写法1
		for i := 0; i < 5; i++ {
			fmt.Println("hello i", i)
		}
		//写法2
		j := 5
		for j <= 10 {
			fmt.Println("hello j", j)
			j++
		}
		//写法3
		i := 3
		for {
			if i < 6 {
				fmt.Println("hello ~", j)
			} else {
				break
			}
			i++
		}
		//遍历字符串和数组 (遍历字符串和数组,此处只给出两种字符串遍历法,数组后续补充),此处需要注意go中字符串是按照字节拼接而不是字符拼接,所以
		//在go使用的utf8中一个汉字占用3个字节下标显示的方法中 经典for则会出现乱码,所以遍历可能还有中文字符的字符串时请使用range方式遍历否则
		//会产生错误但是可以将字符串强制转成切片遍历则正常
		str := "hello,world!你好,世界"
		for i := 0; i < len(str); i++ {
			fmt.Printf("str %c\n", str[i])
		}
		strRune := []rune(str)
		for i := 0; i < len(strRune); i++ {
			fmt.Printf(" strRune %c\n", strRune[i])
		}
		for index, val := range str {
			fmt.Printf("字符:%c === 下标 %d \n", val, index)
		}
	}

四、函数

//概念:
//	为完成某一功能的程序指令(语句)的集合,成为函数,在go中分为自定义函数和系统函数
//语法:
	func 函数名(形参列表) (返回值类型列表){
		//执行语句
		return 返回值列表
	}
//例如:
func NaN() float64 ... //函数返回一个IEEE 754“这不是一个数字”值

五、包

1.import 是写src下的包所在的文件夹abv/edf,然后用包名.函数名来调用包内的函数
2.一般情况下包名和文件夹名保持一致
3.在引包的时候,路径从GOPATH的src开始,不用带src编译器会从src下开始找\
4.为了让其他包的文件可以访问本包的函数,需要将函数大写
5.utils "abc/def/util" 此时 utils为当前包的别名
6.同一个包(package)不能有重名函数
7.如果需要编译成一个可执行文件需要将包名声明为 main 即 package main,这是语法规范,如果是写一个库,则包名可以自定义
8.在$GOPATH下进行打包 build -o 需要指定到main包

六、库文件

1.在编译.go文件之后,会在pkg目录下生成.a库文件,此文件内容是二进制的可以供别人调用,可以起到对源文件隔离的作用

七、函数调用机制

1.在调用一个函数时候会给该函数分配一个新的空间,编译器会通过自身处理让这个新的空间和其他的栈空间区分开来
2.在每个函数对应的栈中,数据空间是独立的,不会相互混淆
3.当一个函数调用完毕(执行完毕),程序会销毁这个函数对应的栈空间

八、递归调用

//求结果
func main() {
	//写法1
	test(4)

}
func test(i int) {
	if i > 2 {
		i--
		test(i)
	}
	fmt.Println(i)
}
//结果
2
2
3
---
分析
  栈

test栈
因为2!>2所以此时
输出语句 2 输出后栈消失回到下一个栈

test栈
因为3>2所以此时
n = 2
输出语句 2 输出后栈消失回到下一个栈

test栈
因为4>2所以此时
n = 3
输出语句 3 输出后栈消失

main栈
test(4)

九、函数注意事项

//1.基本数据类型和数组默认都是值传递,即进行值拷贝,在函数内修改不会影响到原来的值(java中数组传递的是引用类型,在函数内是可以修改到函数外的数组的)
	func main() {
		mum := 5
		fmt.Println("num = ", mum)
		test(mum)
		fmt.Println("num = ", mum)
	}
	func test(i int) {
		i = i + 1
	}
//结果
	num =  5
	num =  5

//2.如果希望函数内的变量可以修改函数的内的变量,可以传入变量的地址,函数内以指针的方式操作变量,从效果上看类似引用
	func main() {
		mum := 5
		fmt.Println("num = ", mum)
		test(&mum)
		fmt.Println("num = ", mum)
	}

	// &取地址  *取指针指向的值
	func test(i *int) {
		*i = *i + 1
	}
//结果
	num =  5
	num =  6
//3.在go中,函数也是一种数据类型,可以赋给一个变量,该变量就是一个函数类型的变量了,通过该变量可以对函数进行调用
	func main() {
		sum := getSum
		fmt.Printf("sum的类型是 = %T,getSum的类型是 = %T \n", sum, getSum)
		sumRes := sum(10, 20)
		fmt.Println("sumRes = ", sumRes)
		getSumRes := getSum(10, 20)
		fmt.Println("getSumRes = ", getSumRes)
	}
	func getSum(n1 int, n2 int) int {
		return n1 + n2
	}
	//结果
	sum的类型是 = func(int, int) int,getSum的类型是 = func(int, int) int
	sumRes =  30
	getSumRes =  30

//4.在go中,函数也可以是形参
	func main() {
		res := myFunc(getSum, 10, 20)
		fmt.Println("res = ", res)
	}
	func getSum(n1 int, n2 int) int {
		return n1 + n2
	}
	func myFunc(funVal func(n1 int, n2 int) int, num1 int, num2 int) int {
		return funVal(num1, num2)
	}
//结果
	res =  30
//5.为了简化数据类型定义,go可以自定义数据类型
	func main() {
		type myInt int //相当于给int起了一个叫做myInt的别名,但myInt和int不是同一个数据类型,是两个不同的数据类型,互相之间需要强转才能使用
		var num myInt = 10
		fmt.Println("num = ", num)

		res := myFunc(getSum, 10, 20)
		fmt.Println("res = ", res)

	}
	func getSum(n1 int, n2 int) int {
		return n1 + n2
	}

	type myFuncType func(int, int) int //自定义方法类型
	func myFunc(funVal myFuncType, num1 int, num2 int) int {
		return funVal(num1, num2)
	}
//结果
	num =  10
	res =  30

//6.go支持对返回值命名
	func main() {
		sumN, subN := getSum(10, 20)
		fmt.Println("sumN = ", sumN, "subN = ", subN)
	}
	func getSum(n1 int, n2 int) (sum int, sub int) {
		sum = n1 + n2
		sub = n1 - n2
		return
	}
//结果
	umN =  30 subN =  -10

//7.使用_标识符,忽略返回值
//8.支持0-多个可变参数
	func main() {
		sumN := getSum2(10, 20, 30)
		fmt.Println("sumN = ", sumN)
	}

	//案例:1到多个可变参数的求和
	func getSum2(arg1 int, args ...int) (sum int) {
		sum = arg1
		//args是一个切片
		for i := range args {
			sum += args[i]
		}
		return
	}
//结果
	sumN =  60

十、init函数

1.每一个源文件都可以包含一个init函数,该函数会在main函数之前,被Go运行框架调用

	func main() {
		fmt.Println("hello main")
	}
	func init() {
		fmt.Println("hello init")
	}
//结果
	hello init
	hello main

2.如果一个文件同时包含全局变量定义,main,init则执行流程是 全局变量定义

//-> init -> main
	var age = test()

	func test() int {
		fmt.Println("hello test")
		return 18
	}
	func main() {
		fmt.Println("hello main and here's age is ", age)
	}
	func init() {
		fmt.Println("hello init")
	}
//结果
	hello test
	hello init
	hello main and here's age is  18

3.init函数主要是完成一些初始化工作
4.导包:当main包函数使用了别的包,那么首先执行被引入的变量定义,然后是被引入的包的init函数然后才是main包的变量定义,init函数最后是main函数

总结

好看的图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值