文章目录

  • **基础语法:**
  • 1.变量定义
  • 2.变量类型
  • 3.常量与枚举
  • 4.条件语句
  • 5.循环语句
  • 6.函数
  • 7.指针
  • **内建容器:**
  • 1.数组
  • 2.Slice(切片)概念 ★★★★★
  • 3.切片的操作


基础语法:

1.变量定义

func variableZeroValue(){
	var a int //默认值0
	var s string //默认值""
	fmt.Printf("%d %q\n", a, s)
}

func variableInitValue(){
	var s int = 3
	var s string = "abc"
	fmt.Println(a, s)
}
//或者
func variableInitValue(){
	var a, b int = 3, 4 //不赋初值也可以
	var s string = "abc"
	fmt.Println(a, b, s)
}
//不指定类型,会自动辨认类型

//写在一行(不需要指定类型,自动辨认类型)
func variableTypeDeduction(){
	var a, b, c, s = 3, 4, true, "Hello" 
	fmt.Println(a, b, c, s)
}
//或者
func variableShorter(){
	a, b, c, s := 3, 4, true, "Hello" 
	b = 5
	//第一次=前边一定要有:
	//后边=前有:相当于新定义变量
	fmt.Println(a, b, c, s)
}

//在函数外部,只能用var定义不能用 “:”
//包变量,没有全局变量这种书法
var a = 3
var s = "Hello"
var t = true
//或者
var (
	a = 3
	s = "Hello"
	t = true
)
2.变量类型
  • bool String
  • (u)int (u)int8 (u)int16 (u)int32 (u)int64 uintptr
  • byte rune(这个相当于其他语言的char,为了应对多国语言)
  • float32 float64 comples64(复数) comples128

①需要回顾下复数看这里:

◆例如 $ i = \sqrt{-1} $ 的结果在实数范围内就无法表示,必须借助复数。
 ◆复数:$ 3 + 4i $
 ◆$ |3 + 4i| = \sqrt{32+42} = 5 $
 ◆$ i^2 = -1,i^3 = -i,i^4 = 1 $
 ◆$ e^{iφ} = cosφ + i sinφ |e^iφ| = \sqrt{cos^2φ + sin^2φ} = 1 $
 ◆$ e^0 = 1, e^{i\dfrac{π}{2}} = i$
 ◆$ e^{iπ} = -1=>e^{iπ} +1 = 0 (欧拉公式,0/1你懂得,注意), e^{i\dfrac{3π}{2}} = -i, e^{i2π} = 1$
//下面看个复数的例子
func euler(){
	c := 3 + 4i//还记得函数里可以用:定义变量吗?3 + 4i会自动识别为复数
	fmt.Println(cmplx.Abs(c))//取模,输出5
}

//再看一个欧拉公式的例子
func euler(){
	fmt.Println(
		cmplx.Exp(1i * math.Pi) + 1//Exp()是e的多少次方,1i是为了让编译器把i识别为复数
		//或者
		cmplx.Pow(math.E, 1i * math.Pi) + 1)//Pow()是指定底数和指数,输出结果为实部0的数复数
}

//这个因为是float的所以存在误差
//可以用Printf指定为%.3f(根据情况自己调节精度),输出结果为实际想要的
//另外python也是这样,输出结果跟Go一样

②强制类型转换(Go只有强制类型转换,没有隐式类型转换):
直接看个例子:

func triangle(){
	//勾股定理,3,4,5
	var a, b int = 3, 4
	var c int
	c = math.Sqrt(a*a + b*b)//错误
	c = int(math.Sqrt(float64(a*a + b*b)))//正确
	fmt.Println(c)
	//Sqrt参数为float64,返回结果为int,输出结果为5
	//问题:float在编程语言中是存在误差的,解决方案?
}
3.常量与枚举

☆常量:
◆const filename = “abc.txt”
◆xonst 数值可以作为各种类型使用
◆const a, b = 3, 4(后面用可以不用抢转,自己当所需类型去使用)

func comsts(){
	//指定类型,不指定类型都可以
	const filename string = "abc.txt"
	const a, b = 3, 4
}

func comsts(){
	const filename = "abc.txt"
	const a, b = 3, 4
	var c int//下面需要强制转换
	c = int(math.Sqrt(float64(a*a + b*b)))
	fmt.Println(filename,c)
}

func comsts(){
	const filename = "abc.txt"
	const a, b = 3, 4
	var c//下面不需要强制转换
	c = int(math.Sqrt(a*a + b*b))
	fmt.Println(filename,c)
}

func comsts(){
	const (
		filename = "abc.txt"
		a, b = 3, 4
	)
	var c//下面不需要强制转换
	c = int(math.Sqrt(a*a + b*b))
	fmt.Println(filename,c)
}

☆枚举

func enums(){
	const (
		cpp = 0
		java = 1
		python = 2
		golang = 3
		javascript = 4
		PHP = 5
	)
	fmt.Println(cpp, java, python, golang, javascript, PHP)
}

//或者
func enums(){
	const (
		cpp = iota//iota可以自增,是个种子
		_
		python
		golang
		javascript
		PHP
	)
	fmt.Println(cpp, _, python, golang, javascript, PHP)
}

//或者
func enums(){
	// b kb mb gb tb pb
	const (
		b = 1 << (10 * iota)
		kb
		mb
		gb
		tb
		pb
	)
	fmt.Println(b, kb, mb, gb, tb, pb)
}
4.条件语句

if语句:

func main(){
	const filename = "abc.txt"
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("%s\n", contents)
	}
}

//或者

func main(){
	const filename = "abc.txt"
	if contents, err := ioutil.ReadFile(filename); err != nil{
		fmt.Println(err)
	} else {
		fmt.Printf("%s\n", contents)
	}
	//出了if语句contents是不能访问的
	
}

switch语句:(switch会自动break,除非使用fallthrough)

func eval(a, b int, op string) int {//参数名,返回类型
	var result int
	switch op {
		case "+":
			result = a + b
		case "-":
			result = a - b
		case "*":
			result = a * b
		case "/":
			result = a / b
		default:
			panic("unsupported operator:" + op)//中断并打印错误
		return result
	}
	
}

//另外一种switch用法:
func grade(score int) string {
	switch {
		g := ""
		case score < 0 || score > 100:
			panic("Wrong score:" + score)
		case score < 60:
			g = "D"
		case score < 80:
			g = "C"
		case score < 90:
			g = "B"
		case score < 100:
			g = "A"
	}
	return g
}
5.循环语句

for循环,没有while:

sum := 0
for i := 1; i <= 100; i++ {
	sum += i
}
//for的条件里不需要括号
//for的条件里可以省略初始条件,结束条件,递增条件


//下几个例子

//import也可以用()一块包含进来
import (
	"fmt"
	"strconv"
)

//省略初始条件
//把一个数转换成二进制
func convertToBin(v int) string {
	result := ""
	for ; v > 0; v /= 2 {
		lsb := v % 2
		result = strconv.Itoa(lsb) + result//strconv.Itoa转换string
	}
	return result
}

// 省略递增条件
func readFile(filename string) string {
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	
	scanner := bufio.NewScanner(file)

	for scanner.Scan() {//相当于while 
		fmt.Println(scanner.Teaxt())
	}
}

//省略所有,死循环
for {
	//TODO,后期并发编程,通信等等会用到
}
6.函数
//返回一个值
func eval(a, b int, op string) int {
	//TODO
}


//返回两个值或者多个值(返回商和余数)
func div(a, b int) (int int) {
	return a / b, a % b
}
//或者
func div(a, b int) (q, r int) {
	q = a / b
	r = a % b
	return
	//另外在idea等IDE环境下,如果使用本函数,会自动生成q,r作为返回值接收,这个可以修改
}

/*********************************************/

//Go定义的变量一定要用到,否则编译器会报错
//,当有两个返回值,而又想用其中一个时
//q, _ = div(13, 3)
//return q | 其他操作 即可

/*********************************************/

//还可用于错误返回
func eval(a, b int, op string) (int, error) {
	switch op {
		case "+":
			return a + b, nil
		case "-":
			return a - b, nil
		case "*":
			return a * b, nil
		case "/":
			return a / b, nil
		default:
			return 0, fmt.Errorf(
				"unsupported operator: %s", op)
	}
	
}

提一下函数式编程:
把上边的eval改写下:

func apply(op func(int, int) int,a, b int) int {
	return op(a, b)
}

//便于理解,加入辅助代码
func apply(op func(int, int) int,a, b int) int {
	p := reflect.ValueOf(op).Pointer()//反射拿到函数指针
	opName := runntime.FuncForPC(p).Name()//间接获取名字
	fmt.Printf("Calling function %s with args " + "(%d, %d)", opName, a, b)
	return op(a, b)
}

可变参数(示例):

fuc sum(numbers ...int) int {
	s := 0
	for i := range numbers {
		s += numbers[i]
	}
	return s 
}

注: 没有函数重载等等比较花哨的方式

7.指针
var a int = 2
var pa *int = &a
*pa = 3
fmt.Println(a)

★★★(不要害怕,比C简单多了)基本使用跟C、C++一样,但指针不能运算,所以简单
★★★ 如果不使用指针全是值传递

内建容器:

1.数组

◆数组定义

func main() {
	//不赋初值,默认值为0
	var arr1 [5]int
	//使用:时,必须赋初值
	arr2 := [3]int{1, 3, 5}
	//如果需要让编译器自动识别长度
	arr3 := [...]int{2, 4, 6, 8, 10}
	fmt.Println(arr1, arr2, arr3)
	//定义一个为维数组,不赋初值默认为0
	var grid [4][5]int
	fmt.Println(grid)
}

◆数组遍历

//常规做法
for i := 0; i < len(arr3); i++ {
	fmt.Println(arr3[i])
}

/*********************/
/*****推荐使用range****/
/******数组是值传递*****/
/*********************/
//或者
for i := range arr3 {//range可以获取数组下标
	fmt.Println(arr3[i])
}
//或者
for i, v := range arr3 {//同时获取value属性
	fmt.Println(i, v)
}
//或者
for _, v := range arr3 {//同时获取value属性
	fmt.Println(v)//只打印值
}
2.Slice(切片)概念 ★★★★★
// 官方文档说Slice是一个视图,所以不是值传递
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	s := arr[2:6]//前闭后开 


	//再看一个例子
	func updateSlice(s []int) {
		s[0] = 100
	}

	func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	fmt.Println("arr[2:6] = ", arr[2:6])
	fmt.Println("arr[:6] = ", arr[:6])
	s1 := arr[2:]
	fmt.Println("s1 = ", s1)
	s2 := arr[:]
	fmt.Println("s2 = ", s2)
	
	fmt.Println("After updateSlice(s1)")
	updateSlice(s1)
	fmt.Println(s1)
	fmt.Println(arr)
	}

go语言学习群 go语言入门指南_go语言学习群

思考一个问题:

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
arr[0], arr[2] = 0, 2
s1 = arr[2:6]
s2 = s1[3:5]
//请问s1, s2分别是?

go语言学习群 go语言入门指南_bc_02

go语言学习群 go语言入门指南_bc_03

fmt.Printf("s1=%v, len(s1)=%d, cap(s1)=%d\n", s1, len(s1), cap(s1))
fmt.Printf("s2=%v, len(s2)=%d, cap(s2)=%d\n", s2, len(s2), cap(s2))

切片可以向后扩展,不可以向前!

3.切片的操作

(持续更新中)