基本语法
简单记录一下学习的几个demo。
格式化字符串
fmt包下,主要分下面两个:
Sprintf:根据格式化参数生成格式化的字符串并返回该字符串。Printf:根据格式化参数生成格式化的字符串并写入标准输出。
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库,后面直接看例子吧,简单给几个常用的。
- os库:
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