fupanc's blog

基本语法

简单记录一下学习的几个demo。

格式化字符串

fmt包下,主要分下面两个:

package main

import "fmt"

func main() {
	var age = 123
	var name = "fupanc"
	var whole_info = "My Age is %d, My name is %s,thank you"

	var final = fmt.Sprintf(whole_info, age, name)
	fmt.Println(final)

	fmt.Printf(whole_info, age, name)
}

注意Println()的输出是会自动换行的,但是Printf()的输出是不会自动换行的。

变量赋值

package main

import "fmt"

func main() {
	//声明类型再赋值
	var age, class int
	age, class = 22, 3
	//赋值时声明类型
	var name string = "fupanc"
	//直接赋值,自动判断类型,但是需要注意变量不能被声明过
	sex := "boy"
	//直接赋值,自动判断类型
	var whole_string = "My name is %s, My age is %d, My class is %d, My sex is %s"
	fmt.Printf(whole_string, name, age, class, sex)
}

条件语句

if语句

package main

import "fmt"

func main() {
	var isAdmin bool

	var age int = 3
	var name string = "fupanc"

	if name == "fupanc" {
		isAdmin = true
	}

	var whole_string string = "My name is %s, My age is %d"
	if isAdmin {
		fmt.Printf(whole_string, name, age)
	}
}

if…else语句

package main

import "fmt"

func main() {
	var isAdmin bool

	var age int = 3
	var name string = "admin123"

	if name == "fupanc" {
		isAdmin = true
	} else {
		isAdmin = false
	}

	var whole_string string = "My name is %s, My age is %d"
	if isAdmin {
		fmt.Printf(whole_string, name, age)
	} else {
		fmt.Printf(whole_string, name, age)
	}
}

if嵌套

package main

import "fmt"

func main() {
	var isAdmin bool

	var age int = 3
	var name string = "admin123"

	if name == "fupanc" {
		isAdmin = true
	} else {
		isAdmin = false
		if age < 5 {
			isAdmin = true
		}
	}

	var whole_string string = "My name is %s, My age is %d, admin: %t"
	if isAdmin {
		fmt.Printf(whole_string, name, age, isAdmin)
	} else {
		fmt.Printf(whole_string, name, age, isAdmin)
	}
}

//output:My name is admin123, My age is 3, admin: true

switch语句

package main

import "fmt"

func main() {
	//var age int = 3
	switch age := 4; age {
	case 1:
		fmt.Printf("My age is %d\n", age)
	case 2:
		fmt.Printf("My age is %d\n", age)
	case 3:
		fmt.Printf("My age is %d\n", age)
	default:
		fmt.Println("No match")
	}
}

循环语句

都通过for语句来进行。for循环可以遍历数组、Map等。

for循环:

package main

import "fmt"

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

循环获取:

package main

import "fmt"

func main() {
	name_list := []string{"fupanc", "admin123"}
	for _, name := range name_list {
		fmt.Println(name)
	}
}

无限循环:

package main

import "fmt"

func main() {
	isAdmin := true
	sum := 0
	for isAdmin {
		sum += 1
		if sum > 10 {
			break
		}
	}
	fmt.Println(sum)
}

函数定义与使用

package main

import "fmt"

func main() {
	name_list := []string{"fupanc", "admin123"}
	get_all_name(name_list)
	fmt.Println("=====example2=====")
	get_all_name_first := func(name []string) string {
		return name[0]
	}
	fmt.Println(get_all_name_first(name_list))
}

func get_all_name(name_list []string) {
	for _, name := range name_list {
		fmt.Println(name)
	}
}

指针

package main

import "fmt"

func main() {
	//一个确定的值
	name_list := "fupanc"

	//声明一个指针变量,,指向字符串类型
	var point *string

	//给指针变量赋值,也就是会指向name_list变量的地址
	point = &name_list

	//输出对比
	fmt.Println("name_list的地址为:", &name_list)
	fmt.Println("point指针变量的值:", point)
	fmt.Println("point指针变量本身的地址:", &point)
	fmt.Println("point指针变量指向的地址的内容:", *point) //在指针变量前就一个*来表示取对应地址上的内容
}

注意指针指向什么类型的数据,就要声明为什么类型的指针。

结构体

package main

import "fmt"

type students_list struct {
	name string
	age  int
	sex  string
} //其实结构体就可以理解成重新定义了一个变量类型,同样存在数组类型等等,用法有一点点区别而已

func main() {
	//方式一:
	students1 := students_list{"fupanc", 11, "boy"}
	fmt.Println("students1的name为:", students1.name)
	fmt.Println("students1的age为:", students1.age)
	fmt.Println("students1的sex为:", students1.sex)
	fmt.Println("====================")
	//方式二:
	var students2 students_list
	students2.name = "fupanc2"
	students2.age = 22
	fmt.Println("students2的name为:", students2.name)
	fmt.Println("students2的age为:", students2.age)
	fmt.Println("====================")
	//指针实现
	students3 := students_list{"red", 11, "girl"}
	var point_1 *students_list
	point_1 = &students3
	//输出方式一:先获取实例在获取对应内容
	output_test := *point_1
	fmt.Println("point_1指针指向的name为:", output_test.name)
	//输出方式二:同样获取实例在获取对应内容,但是需要使用括号来修改优先级,否则不能直接获取
	fmt.Println("point_1指针指向的age为:", (*point_1).age)
	//输出方式三:结构体指针直接用.来访问成员(go的语法糖,记着就行)
	fmt.Println("point_1指针指向的sex为:", point_1.sex)
}

可以理解一下,还是挺有意思的。

切片

其实就是动态数组的利用吧,但是没有那么简单,需注意的一个点:

如下代码:

package main

import "fmt"

func main() {
	//切片定义:
	example_a := []int{1, 2, 3, 4, 5}
	fmt.Println("example_a全部内容为:", example_a)
	fmt.Println("截取部分,example_a[:4]:", example_a[:4])
	//添加元素,主要使用append()内置函数
	example_a = append(example_a, 6)
	fmt.Println(example_a)

	fmt.Println("========example_other========")
	//切片引用
	example_part_a := example_a[:3]
	fmt.Println(example_part_a)
	example_part_b := example_a[2:4]
	fmt.Println(example_part_b)

	fmt.Println("--------修改值-------")
	example_part_a[2] = 8
	fmt.Println("example_part_a:", example_part_a)
	fmt.Println("example_part_b:", example_part_b)
	fmt.Println("example_a:", example_a)
}

输出为:

example_a全部内容为: [1 2 3 4 5]
截取部分,example_a[:4]: [1 2 3 4]
[1 2 3 4 5 6]
========example_other========
[1 2 3]
[3 4]
--------修改值-------
example_part_a: [1 2 8]
example_part_b: [8 4]
example_a: [1 2 8 4 5 6]

可以看到修改切片的值,底层数组已经另一个切片的值也变了,切片共享底层数组(存在安全隐患?后续还需要出题再看看)。以及了解一下也是存在append()这些内置函数即可。

其实大部分时候直接把其看成一个可控的数组即可。

Map(集合)

就是无序的键值对的集合。通过键来获取到对应的值,代码如下:

package main

import "fmt"

func main() {
	map_example := make(map[string]int, 4)
	map_example["a"] = 1
	fmt.Println(map_example["a"])

	map_example_list := map[string]int{
		"fupanc's age": 22,
		"Mike's age":   23,
	}
	fmt.Println("年龄和为:", map_example_list["fupanc's age"]+map_example_list["Mike's age"])
	fmt.Println(len(map_example_list))
	delete(map_example_list, "Mike's age")
	fmt.Println(len(map_example_list))

}

输出为:

1
年龄和为: 45
2
1

同样用了内置函数:delete()–删除元素、len()集合键值对个数,理解一下即可。

类型转换

就简单说两种吧,具体后面再看。

1.数值类型转换(直接使用内置函数):

package main

import "fmt"

func main() {
	var age float64 = 1.222
	b := int(age)
	fmt.Println("转换前的数值:", age)
	fmt.Println("转换后的数值:", b)
}

等等,还有很多内置函数。

2.数字与字符串之间相互转换(主要使用strconv包):

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var age int = 22
	b := strconv.Itoa(age)

	c, err := strconv.Atoi(b)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("转换前的数值:%d", age)
	fmt.Printf(" ====> 转换后的数值:%s", b)
	fmt.Printf(" ====> 再转换回数值类型并+1:%d", c+1)
}

实现了int转string再转int,注意Atoi()函数会return两个值,并且正常转换的话第二个return的值为nil(空值),否则会return报错信息,这里不多说。

接口(结构体方法、接口变量)

先看结构体方法的代码:

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (s *Person) getName() string {
	return s.name
}

func (s *Person) setAge(age int) {
	s.age = age
}

func (s *Person) getAge() int {
	return s.age
}

func main() {
	person_a := Person{"fupanc", 22} //语法糖,也可以写成这样:person_a := &Person{"fupanc", 22}
	fmt.Println("修改前:")
	fmt.Println("name为:", person_a.getName())
	fmt.Println("age为:", person_a.getAge())

	fmt.Println("修改后:")
	person_a.setAge(18)
	fmt.Println("age为:", person_a.getAge())
}

大概就是可以将struct结构体看成java中的类,以此来操作对应结构体的方法以及其存储的变量。

接口实现的代码:

package main

import "fmt"

type Class interface {
	getClass() int
}

type Person struct {
	name  string
	age   int
	class int
}

func (s *Person) getClass() int {
	return s.class
}

func (s *Person) getName() string {
	return s.name
}

type Person2 struct {
	name  string
	class int
}

func (p *Person2) getClass() int {
	return p.class
}

func (p *Person2) getName() string {
	return p.name
}

func main() {
	var c Class

	person_a := &Person{"fupanc", 22, 7}
	//赋给接口变量
	c = person_a
	fmt.Printf("%s's class is %d \n", person_a.getName(), c.getClass())

	bus_b := &Person2{"zhangsan", 99}
	c = bus_b

	fmt.Printf("%s's class is %d", bus_b.getName(), c.getClass())
}

只要结构体方法实现了指针的方法,隐式就会认为实现了对应的接口,这里使用接口变量,方便调用。理解就行,后面再看具体用不用得到。

错误处理

使用errors包,在需要有需求的地方设置报错,从而来达到想要的效果:

package main

import "fmt"
import "errors"

func main() {
	name := "fupanc"
	if name != "admin" {
		fmt.Println(errors.New("not admin"))
	} else {
		fmt.Println("welcome admin")
	}
}

文件处理

这个值得看一下,毕竟都是文件处理了,还是很可能存在安全问题的。

主要涉及到os、io、bufio库,后面直接看例子吧,简单给几个常用的。

package main

import (
	"fmt"
	"os"
)
func main() {
	//demo1(文件创建并写入内容):
	//创建文件但没有内容
	file, err := os.Create("test.txt")
	if err != nil {
		panic(err)
	}
	//注意释放对应的资源
	defer file.Close()

	_, error1 := file.WriteString("It is created by fupanc")
	if error1 != nil {
		panic(err)
	}

	//demo2(文件读取):
	content, err := os.ReadFile("test.txt")
	if err != nil {
		panic(err)
	}
	fmt.Println("File Content:", string(content))

	//demo3(文件删除):
	err5 := os.Remove("test.txt")
	if err5 != nil {
		panic(err)
	}
}

成功实现文件创建、内容写入、文件删除。

os库还可以做很多事,比如os.Mkdir()创建目录等等,有点类似于python的os库。等等另外两个库这里就不多说了。

参考文章:

https://www.topgoer.com/%E5%B8%B8%E7%94%A8%E6%A0%87%E5%87%86%E5%BA%93/IO%E6%93%8D%E4%BD%9C.html

https://www.runoob.com/go/go-tutorial.html

https://tour.go-zh.org/welcome/1