初识Go语言

发布于:2025-09-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

go相关命令

//对go源码进行编译,生成.exe文件
go build go文件名
//直接运行go源码(生成.exe文件执行后,又删除.exe文件)
go run go文件名

go中的package和import

/*package:用来声明这个文件是属于哪个包的*/
package main

/*import:导入包,对包中的函数进行引用和复用*/
import "fmt"

//main函数是程序的入口
func main() {
	fmt.Println("hello world")  //自带换行
    fmt.Printf("占位符格式化打印,传递过来的值,这个值用 %s 占位", "运维开发")
    fmt.Print("hello world")   //不换行
    fmt.Println("hello", "world")  //类似于python的拼接
    fmtEnv := fmt.Sprintf("你好%s,大小%d", "hello", 5)  //将拼接后的字符串赋值给变量
	fmt.Println(fmtEnv)   //打印变量
    fmt.Println(3.1415926)   //打印整数
}

什么是包:可以理解为go源码的集合,也是一种比较高级的代码复用方案

  • 我们可以把一些复用的代码或功能函数封装在一起,然后形成一个包,可以被其他包或go文件进行引用

什么是main包:main是一个特殊的包,一个可执行的程序有且只有一个main包

什么是main函数:main函数是整个程序的入口,如果一个程序没有main函数是无法正常执行程序的

花括号:表示一个代码块,花括号内的代码属于同一个块内,也可以说属于同一个域内

函数使用func进行声明

人机交互

package main

import "fmt"

func main() {
	//方式1:fmt.Scanln(指针)
	var name string
	var age byte
	var salary float32
	var isPass bool
	//当程序执行到fmt.Scanln(&name),程序会停止在这里,等待用户输入,并回车
	fmt.Printf("请输入姓名:")
	fmt.Scanln(&name)

	fmt.Printf("请输入年龄:")
	fmt.Scanln(&age)

	fmt.Printf("请输入薪水:")
	fmt.Scanln(&salary)

	fmt.Printf("是否通过考试(true or flase):")
	fmt.Scanln(&isPass)
	fmt.Printf("名字:%v\n年龄:%v\n薪水:%v\n是否通过考试:%v", name, age, salary, isPass)
}
package main

import "fmt"

func main() {
	//方式2:fmt.Scanf()
	var name string
	var age byte
	var salary float32
	var isPass bool
	fmt.Printf("输入姓名,年龄,薪水,是否通过考试:")
	fmt.Scanf("%s %d %f %t", &name, &age, &salary, &isPass)
	fmt.Printf("名字:%v\n年龄:%v\n薪水:%v\n是否通过考试:%v", name, age, salary, isPass)
}

变量

在这里插入图片描述

package main

import "fmt"
//函数外赋值
var address string = "172.25.254.80"

add := "gaga"   //会报错
func main() {
  //var 变量名 变量类型
	var name1 string  //先定义
	name1 = "huazi"   //再赋值
	fmt.Println(name1)
    
    //一次性定义多个相同类型的变量
	var name2, user string = "hua", "huazi" 
	fmt.Println(name2, user)
    
    //一次性定义多个不同类型的变量
	var (
		age1  int    = 18
		name3 string = "huazi"
	)
	fmt.Println(name3, age1)
    
    //当省略类型后,go会自动判断,自动转换为强数据类型
	var (
		name4 = "huazi"
		age2  = 18
	)
	fmt.Println(name4, age2)
    
    //当省略了var,只能再函数内使用,要用:= ,称之为语法糖
    //相当于var变成了:
	name5 := "huazi"   //我们成为语法糖写法
	age3 := 18
	fmt.Println(name5, age3)
    
    //交换变量的值
	name6 := "hua"
	name7 := "huazi"
	name6, name7 = name7, name6 
	fmt.Println(name6, name7)
    
    //reflect.TypeOf(变量名)  打印变量的类型或者使用%T来表示类型
	fmt.Println(reflect.TypeOf(name6))
}

在函数外定义并赋值的变量是包级别的变量,这种变量可以不对其进行使用。但是在函数中定义的变量必须得到使用

函数外不能使用语法糖来定义变量

常量

package main

import (
	"fmt"
)

const ADDRESS string = "172.25.254.80"

func main() {
	fmt.Println(ADDRESS)

	//一次性定义多个相同类型的变量
	const name1, name2 string = "hua", "huazi"
	fmt.Println(name1, name2)

	//一次性定义多个不同类型的常量
	const (
		name3 string = "yao"
		age int = 18
	)
	fmt.Println(name3, age)

	//常量可以省略类型,但是不能省略const
	const (
		name4 = "ze"
		age1 = 18
	)
	fmt.Println(name4, age1)
    
    age1 = 20   //会报错,因为常量不能修改
    
	const (
		num1 int = 1
		num2
		num3
		str1 string = "hua"
		str2
		str3
	)
	fmt.Println(num1, num2, num3)  //1 1 1
    fmt.Println(str1, str2, str3)  //hua hua hua
    
    //枚举(const+iota),iota的基数是0
    	const (
		e1 int = (1 + iota) * 10
		e2
		e3
	)
	fmt.Println(e1, e2, e3)   //10 20 30
}

常量在函数内外都是可以不进行使用的

%v

在 Go 语言中,%v 是一个通用的格式化动词format verb),用于 fmt 包中的格式化函数,如 fmt.Printffmt.Sprintffmt.Fprintf 等。%v 可以用于不同类型的值,并会根据值的类型输出其默认的字符串表示。

以下是一些示例,展示了 %v 如何处理不同类型的数据:

  1. 整数

    fmt.Printf("%v\n", 42)         // 输出: 42
    
  2. 浮点数

    fmt.Printf("%v\n", 3.14)       // 输出: 3.14
    
  3. 字符串

    fmt.Printf("%v\n", "hello")    // 输出: hello
    
  4. 布尔值

    fmt.Printf("%v\n", true)       // 输出: true
    
  5. 指针

    var p *int = &age
    fmt.Printf("%v\n", p)          // 输出: 0xc0000180b0(或类似的内存地址)
    
  6. 结构体

    type Person struct {
        Name string
        Age  int
    }
    
    p := Person{Name: "Alice", Age: 30}
    fmt.Printf("%v\n", p)          // 输出: {Alice 30}
    
  7. 切片

    slice := []int{1, 2, 3}
    fmt.Printf("%v\n", slice)      // 输出: [1 2 3]
    
  8. 映射

    m := map[string]int{"a": 1, "b": 2}
    fmt.Printf("%v\n", m)          // 输出: map[a:1 b:2]
    
  9. 接口

    var i interface{} = "world"
    fmt.Printf("%v\n", i)          // 输出: world
    

使用 %v 时,Go会根据值的实际类型选择适当的字符串表示,因此它是一个方便且通用的格式化动词。然而,对于某些特定类型,你可能希望使用更具体的格式化动词以获得更精细的控制。例如,对于整数可以使用 %d,对于浮点数可以使用 %f,对于字符串可以使用 %s 等等。

作用域

  • go中使用{}来定义作用域的范围
  • 使用原则:子语句块中可以使用父语句块中的标识符,父不能使用子的
package main

import (
	"fmt"
)

func main() {
	num1 := 1
	{
		num2 := 2
		fmt.Println(num1)
		fmt.Println(num2)
	}
	//fmt.Println(num2) //报错
}
package main

import (
	"fmt"
)

func printAll() {
	fmt.Println("今天是个好日子")
	fmt.Println("hello world")
	num1 := 1
	fmt.Println(num1)
}
func main() {
	printAll() //调用函数
	//fmt.Println(num1)  报错
}

运算符

  • 算术运算
package main

import "fmt"

//定义参数
func Calculate(num1 int, num2 int) {
	fmt.Printf("num1+num2=%d\n", num1+num2)
	fmt.Printf("num1-num2=%d\n", num1-num2)
	fmt.Printf("num1*num2=%d\n", num1*num2)
	fmt.Printf("num1/num2=%d\n", num1/num2)  //取整
	fmt.Printf("num1取余num2=%d\n", num1%num2)
}

func main() {
	num1 := 1
	num2 := 2
	Calculate(num1, num2)  //值传递
}
  • 字符串拼接
package main

import "fmt"

func stringCalculate(str1 string, str2 string) {
	fmt.Printf("str1+str2=%s\n", str1+str2)
	word := fmt.Sprintf("str1+str2=%s", str1+str2)
	fmt.Println(word)
}

func main() {
	str1 := "hello"
	str2 := "world"
	stringCalculate(str1, str2)
}
//自增自减
	p1 := 8
	p1++
	fmt.Println("p1 =", p1)
	p1--
	fmt.Println("p1 =", p1)
package main

import "fmt"

func main() {
	a := 3
	b := 2
	fmt.Println(a / b)   //取整   1
    fmt.Println(float64(a) / float64(b))  //  1.5小数运算
}

浮点数不能和整数一起运算

float32类型的和float64类型的不能运算

int类型和float类型

package main

import (
	"fmt"
	"math"
	"reflect"
)

func main() {
	// 数值类型:int int8 int16 int32 int64 uint
	// int: 正负数  uint:不带符号的数字 // int
	defaultIntType := 1
	fmt.Println("默认的数值类型是:", reflect.TypeOf(defaultIntType))
	// int和操作系统是有关系的
	// 64位的,int64  32位的 int32
	var int64Num int64 = 1
	fmt.Println("int64Num的数值类型是:", reflect.TypeOf(int64Num))
	var uintNum uint = 1
	fmt.Println("uintNum的数值类型是:", reflect.TypeOf(uintNum))
	fmt.Println("int的取值范围:", math.MinInt, math.MaxInt)
	fmt.Println("uint的取值范围:", uint(math.MaxUint))
	fmt.Println(18446744073709551615 > 9223372036854775807)
	// float float32和float64
	var floatNum1 float64 = 3.14
	var floatNum2 float32 = 3.15
	// floatSum := floatNum1 + floatNum2
	fmt.Println(floatNum1, floatNum2)
}

关系与逻辑运算符

package main

import (
	"fmt"
	"reflect"
)

func main() {
	// 大于, 小于
	fmt.Println(727585 > 727588) // false
	fmt.Println(727585 < 727588) // true
	// 是否相等,  =和==的区别
	fmt.Println("a" == "b") // false
	fmt.Println(3.14 == 3.14)

	s1 := "dukuan"
	s2 := "dotbalo"
	// xxx := s1 == s2
	fmt.Println("s1和s2相等: ", s1 == s2)
	fmt.Println("s1和s2不相等: ", s1 != s2)
	fmt.Println("s1 > s2:", s1 > s2)
	fmt.Println("s2 > s1:", s2 > s1) //字符串是可以比较大小的, ASCII
	// 逻辑与和逻辑或  && ||
	n1 := 1
	n2 := 1
	n3 := 2
	// 与: 所有的表达式都为true,最终的结果就为true
	fmt.Println(n1 == n2 && n2 == n3) // true false => false
	// 或:任意一个为true,最终结果就为true
	fmt.Println(n1 == n2 || reflect.TypeOf(n3).Kind() == reflect.String)
}

if-else

package main

import (
	"fmt"
)

func printWeather(weather string) {
	if weather == "sunny" {
		fmt.Println("今天是晴天")
	} else if weather == "rain" {
		fmt.Println("今天是雨天")
	} else {
		fmt.Println("今天气候不明")
	}
}

func main() {
	weather := "rain"
	printWeather(weather)
}

if的特殊用法

package main

import "fmt"

func backBool() bool {
	return true
}

func main() {
	a := false
	if res := backBool(); res != a { //在判断前,先进行运算
		fmt.Println("true")
	} else {
		fmt.Println("false")
	}
}

switch

package main

import (
	"fmt"
)

func printScore(score int) {
	sc := score / 10
	switch sc {
	case 10, 9:
		fmt.Println("优秀")
        break
	case 8:
		fmt.Println("良好")
	case 7:
		fmt.Println("中等")
	case 6:
		fmt.Println("及格")
	default:
		fmt.Println("不及格")
	}
}

func main() {
	printScore(66)
}

break默认可以省略不写

for

package main

import (
	"fmt"
	"time"
)

func main() {
	count := 0 //记录偶数的个数
	for num := 0; num < 100; num++ {
		if num%2 == 0 {
			fmt.Println("发现一个偶数:", num)
			count++
		}
		time.Sleep(time.Second)   //停顿1秒,second是秒的意思
	}
	fmt.Printf("一共有%d个偶数", count)
}

for实现死循环

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		timeNow := time.Now() //获取当前时间
		// 2006-01-02 15:04:05 go语言的诞生时间
		fmt.Println("当前时间是:", timeNow.Format("2006-01-02 15:04:05"))
		time.Sleep(time.Second * 3) //停顿3秒
	}
}

break与continue

package main

import (
	"fmt"
)

func main() {
	temp := 20
	count := 0
	for {
		if count == 20 {
			fmt.Println("恭喜你找到了", temp)
			break
		} else {
			count++
		}
	}
}
package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 0; i < 100; i++ {
		if i == 88 {
			fmt.Println("我找到了88")
			break
		}
		fmt.Println("现在的数值是:", i)
	}
	time.Sleep(time.Second * 3)
	for i := 0; i < 50; i++ {
		if i == 33 {
			fmt.Println("我找到了33")
			continue
		}
		fmt.Println("现在的数值是:", i)
	}
}

数组

package main

import "fmt"

func main() {
	//数组定义:一组具有相同类型并且长度固定的一个数据集合
	//var 数组名 = [长度]类型{value1,value2}
	var name = [3]string{"小明", "华子", "戈兄"}
	fmt.Println(name) //[小明 华子 戈兄]
	fmt.Println(name[0])
	//修改
	name[0] = "小华"
	fmt.Println(name)
	//for循环访问
	for i := 0; i < 3; i++ {
		fmt.Println(name[i])
	}
	//求数组的长度
	length := len(name)
	fmt.Println(length)

	//range使用
	for i, v := range name {
		fmt.Println(i, v)
	}

	//自动推断长度
	array3 := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(len(array3))
}

切片

package main

import "fmt"

func main() {
	// 切片:切片的长度是不固定的,可以扩容
	// var 切片名称 = []切片类型{value1, value2...}
	var slice1 []int    //先定义切片
	fmt.Println(slice1) // []
	// 切片默认的两个属性:1.切片的长度,表示切片中有多少个元素  2.切片的容量,表示切片中最大可以放多少个元素
	fmt.Println("切片的默认长度是:", len(slice1)) // 0
	fmt.Println("切片的默认容量:", cap(slice1))  // 0

	// 添加元素
	slice1 = append(slice1, 1, 2, 3, 4)
	fmt.Println(slice1)             // [1 2 3 4]
	fmt.Println("长度:", len(slice1)) // 4
	fmt.Println("容量:", cap(slice1)) // 4
	// 修改数据
	slice1[0] = 88
	fmt.Println(slice1) //  [88 2 3 4]

	//定义切片并初始化
	var slice2 = []string{"切片1", "切片2", "切片3"}
	fmt.Println(slice2)                //  [0 0 0 0 0]
	fmt.Println("切片的长度:", len(slice2)) // 3
	fmt.Println("切片的容量:", cap(slice2)) // 3
	slice2 = append(slice2, "切片4", "切片5")
	fmt.Println(slice2) //  [0 0 0 0 0]

	//第二种声明方式,指定长度
	slice3 := make([]int, 5, 10)         //5个长度,10个容量
	fmt.Println(slice3)                  // [0 0 0 0 0]
	fmt.Println("切片的默认长度:", len(slice3)) // 5
	fmt.Println("切片的默认容量:", cap(slice3)) // 10
	slice3 = append(slice3, 1, 2, 3)
	fmt.Println(slice3) //  [0 0 0 0 0 1 2 3]

	slice4 := make([]string, 3, 5)
	fmt.Println(slice4) // 默认初始化一个空格
	slice4 = append(slice4, "hua")
	fmt.Println(slice4)

	// for循环遍历
	for i, v := range slice2 {
		fmt.Println(i, v)
	}
}

数组和切片在声明时的区别:数组有长度,切片没有长度

切片截取和元素删除

package main

import "fmt"

func main() {
	var s = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println("最初的数据是:", s)
	fmt.Println("前4位数据:", s[0:4]) //包头不包尾
	fmt.Println("从第5个数据开始:", s[4:])

	//删除一个元素:go语言中删除切片中的元素是通过截取的方式实现的
	s = s[1:] // 删除第一个元素
	fmt.Println(s)
	s = s[:len(s)-1] // 删除最后一个元素
	fmt.Println(s)
	s = append(s[:2], s[3:]...) // 删除第3个元素
	fmt.Println(s)
}

深拷贝与浅拷贝

package main

import "fmt"

func main() {
	str1 := "huazi"
	str2 := str1 //深拷贝
	fmt.Println(str1, str2)  //huazi huazi
	str2 = "hua"
	fmt.Println(str1, str2)   //huazi hua

	//定义一个切片
	slice1 := []int{1, 2, 3, 4, 5, 6}
	slice2 := slice1 //浅拷贝
	fmt.Println(slice1, slice2)  //[1 2 3 4 5 6] [1 2 3 4 5 6]
	slice2[0] = 88
	fmt.Println(slice1, slice2)   //[88 2 3 4 5 6] [88 2 3 4 5 6]
}

深拷贝:复制一个变量时,会创建一个全新的变量,并且将原始数据复制给新变量,新变量在内存中会是一个新的地址,并且两个变量修改时不会影响其他变量

浅拷贝:复制一个变量时,也会创建一个新的变量,但是两个变量共享底层的数据,也就是新旧变量会指向同一个数据的内存地址,实际上算是引用同一个数据,也就是意味着任意一个变量发生变更,其他变量也会被修改

值类型:复制变量的时候是深拷贝,值类型包括(int,float,string,struct,array,bool)

引用类型:复制变量的时候是浅拷贝,引用类型包括:(slice,map,channel,interface)

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	str1 := "huazi"
	str2 := str1 //深拷贝
	fmt.Println(str1, str2)
	str2 = "hua"
	fmt.Println(str1, str2)

	//定义一个切片
	slice1 := []int{1, 2, 3, 4, 5, 6}
	//如何对切片进行深拷贝呢
	slice2 := make([]int, len(slice1), cap(slice1))
	copy(slice2, slice1) //深拷贝
	slice2[0] = 88       //对slice2的修改不影响slice1
	fmt.Println(slice1, slice2)

	//打印内存地址
	fmt.Println("slice1的内存地址", unsafe.Pointer(&slice1))       //1
	fmt.Println("slice1[0]的内存地址", unsafe.Pointer(&slice1[0])) //2
	fmt.Println("slice2的内存地址", unsafe.Pointer(&slice2))       //3
	fmt.Println("slice2[0]的内存地址", unsafe.Pointer(&slice2[0])) //4
}

map映射

package main

import "fmt"

func main() {
	// var map名 = map[type]type{key1:value1, key2:value2......}
	teacherAge := make(map[string]int)
	fmt.Println("map的初始化值", teacherAge) //map[]
	teacherAge["huazi"] = 18
	teacherAge["xiaoming"] = 20
	teacherAge["huazi"] = 22
	fmt.Println("赋值后的值", teacherAge) //map[huazi:22 xiaoming:20]

	//在声明变量的时候直接进行赋值操作
	teacherAge1 := map[string]int{
		"d1": 2,
		"d2": 3,
	}
	fmt.Println(teacherAge1) //map[d1:2 d2:3]

	//先用var声明
	var teacherAddress map[string]string
	//再用make声明内存空间
	teacherAddress = make(map[string]string)
	teacherAddress["huazi"] = "洋县"
	teacherAddress["hua"] = "汉川"
	fmt.Println(teacherAddress) //map[hua:汉川 huazi:洋县]

	//访问
	fmt.Println("huazi老师的地址", teacherAddress["huazi"])

	searchName := "hua"
	fmt.Printf("%s老师的地址:%s\n", searchName, teacherAddress[searchName])

	//for range
	for k, v := range teacherAddress {
		fmt.Printf("%s老师的地址:%s\n", k, v)
	}
	fmt.Println("取一个不存在的值:", teacherAddress["hhhh"]) //空字符串

	//map中的ok判断
	value, ok := teacherAddress["hua"] //如果hua这个键不存在返回false,存在返回true
	if ok {
		fmt.Printf("能查看到hua的地址:%s\n", value)
	} else {
		fmt.Printf("不能查到hua的地址\n")
	}

	// 修改值
	teacherAddress["hua"] = "北京"
	fmt.Println("修改后的值:", teacherAddress["hua"])

	// 删除值
	delete(teacherAddress, "huazi")
	fmt.Println("删除后的map:", teacherAddress)
}

切片中嵌套map对象

var slice = []map[type]type
package main

import "fmt"

func main() {
	order1 := map[string]int{
		"宫保鸡丁": 99,
		"糖酸鱼":  88,
	}
	order2 := map[string]int{
		"回锅肉":  66,
		"鱼香肉丝": 89,
	}
	order3 := map[string]int{
		"奶茶": 18,
		"可乐": 3,
	}
	var menu []map[string]int //map[string]int是一个整体
	menu = append(menu, order1, order2, order3)
	fmt.Println(menu)        //[map[宫保鸡丁:99 糖酸鱼:88] map[回锅肉:66 鱼香肉丝:89] map[可乐:3 奶茶:18]]
	for i, v := range menu { //i是下标,v是map对象
		fmt.Printf("第%d天的菜单是:\n", i+1)
		for name, price := range v {
			fmt.Printf("\t菜名:%s,价格:%d\n", name, price)
		}
	}
}

map对象嵌套map对象

var map11 = map[type]map[type]type
package main

import (
	"fmt"
)

func main() {
	//map对象嵌套map对象
	// map[string]map[string]string
	address1 := map[string]string{
		"汉中市": "洋县",
		"宝鸡市": "凤县",
	}
	address2 := map[string]string{
		"武功市": "好县",
		"花市":  "中等县",
	}
	var country map[string]map[string]string
	country = make(map[string]map[string]string)
	country["陕西省"] = address1
	country["浙江省"] = address2
	fmt.Println(country)
	for province, city_map := range country {
		fmt.Printf("%s:\n", province)
		for city, county := range city_map {
			fmt.Printf("\t%s  %s\n", city, county)
		}
	}
}

类型转换

package main

import (
	"fmt"
	"math"
)

// 参数类型为float64,返回值类型为float64
func area(r float64) float64 {
	s := math.Pi * r * r
	return s
}

func main() {
	r := 5                //此时r默认为int类型
	s := area(float64(r)) //需要使用float64()把int转为float64
	fmt.Println("面积是:", s)
}

在这里插入图片描述

package main

import (
	"fmt"
	"reflect"
	"strconv"
)

func main() {
	i1 := 10
	//将int类型转为string类型
	str1 := strconv.Itoa(i1)
	fmt.Println(str1, reflect.TypeOf(str1))

	str2 := "1001"
	//将string类型转为int类型
	i2, _ := strconv.Atoi(str2) //通过_来规避掉函数的返回值
	fmt.Println(i2, reflect.TypeOf(i2))

	// str3 := "100"
	str3 := "100a"
	i3, err := strconv.Atoi(str3) //如果err有值,则转换失败,err为nil则转换成功
	if err != nil {
		// 转换失败
		fmt.Println(err)
		fmt.Println("转换失败,当前值不能转换为数值")
	} else {
		//转换成功
		fmt.Println(err)
		fmt.Println("转换成功", i3)
	}
}
package main

import (
	"fmt"
	"strconv"
)

func main() {
	//将0 1 f t float true Float True FLOAT TRUE等布尔型字符串转为bool类型
	str1 := "t"
	bool1, _ := strconv.ParseBool(str1)
	fmt.Println("转换后的布尔值:", bool1)
}

字符串方法

package main

import (
	"fmt"
	"strings"
)

func main() {
	// 字符串的定义
	// ``  ""
	// "\t \n"  ``
	s := "\t\txxx\n"
	fmt.Println("双引号字符串:", s)
	s2 := `\t\txxx\n`
	fmt.Println("反引号字符串:", s2)
	s3 := `
	我是杜宽
	我主要教授的课程是: 云原生系列,k8s,go,python
	`
	fmt.Println("多行字符串:", s3)
	// 字符长度的计算
	s4 := "dukuan"
	s5 := "杜宽" //中文占用3个字符
	s4Length := len(s4)
	s5Length := len(s5)
	fmt.Println(s4Length, s5Length)
	// 字符串的截取  , 一般
	// s6 := s4[2]
	fmt.Println("前两位:", s4[:2])
	s7 := "dukuan"
	// 大小写转换, 一般
	fmt.Println("转成大写:", strings.ToUpper(s7))
	fmt.Println("首字母大写", strings.Title(s7))
	s8 := "dUKUan"
	fmt.Println("转成小写:", strings.ToLower(s8))
	// 字符串是否包含某个元素 ,还行
	fmt.Println("查看字符串是否包含uk这个元素:", strings.Contains(s7, "uk"))
	fmt.Println("查看字符串是否包含任意一个字符:", strings.ContainsAny(s7, "uw"))
	// 忽略大小写进行比较
	fmt.Println("忽略大小写比较:", strings.EqualFold(s7, s8))
	// 判断字符串中某个元素有多个个
	s9 := "dukuan and dot is me, my age is 18"
	fmt.Println("u在字符串中出现了:", strings.Count(s9, "u"))
	// 字符串拆分 //很多
	s9Split := strings.Split(s9, ",")
	fmt.Println("使用逗号拆分字符串:", s9Split)
	fmt.Println("拆分后的切片的第一个数据:", s9Split[0])
	s9SplitAfter := strings.SplitAfter(s9, ",")
	fmt.Println("使用逗号拆分字符串,并且保留逗号:", s9SplitAfter)
	// 字符串拼接 //很多
	slice1 := []string{"dot", "balo", "du", "kuan"}
	fmt.Println("拼接字符串:", strings.Join(slice1, " "))
	// 是否是某个元素开头的 ,还行
	s10 := "我是一个中国人,我非常热爱中国"
	fmt.Println("字符串是以 ‘我’ 开头的:", strings.HasPrefix(s10, "我"))
	// 此处的视频出现错误,应该是HasSuffix
	fmt.Println("字符串是以 爱 结尾的:", strings.HasSuffix(s10, "爱"))
	// 重复字符串
	fmt.Println("打印五个我:", strings.Repeat("我", 5))
	// 字符串替换 ,还行
	s11 := "dsad3afd3rq3adawdwarq3a"
	fmt.Println("把3替换为dukuan:", strings.ReplaceAll(s11, "3", "dukuan"))
	fmt.Println("把3替换为杜宽:", strings.Replace(s11, "3", "杜宽", 1)) // 0替换所有
	// trim 字符串修剪 ,很多
	s12 := "  dukuan  ,"
	fmt.Println("去掉字符串的前后空格:", strings.Trim(s12, ","))
}

指针和内存地址

package main

import "fmt"

func updateString(s string) {
	s = "这是一个新值"
}
func updateStringWithPointer(s *string) {
	*s = "这是一个新值"
}

func main() {
	var s string
	s = "这是一个字符串"
	fmt.Println("变量s的内存地址是:", &s)
	// sp: 指针
	// 内存地址: 通过&符号进行取值
	sp := &s
	fmt.Println("指针sp:", sp)
	var sp2 *string
	fmt.Println("指针sp2:", sp2) // 指针未进行赋值的时候为nil
	sp2 = &s
	fmt.Println("指针sp2:", sp2)
	// 通过指针获取内存地址的值
	fmt.Println("指针对应内存地址的值:", *sp2)

	updateString(s)
	fmt.Println("修改后的s:", s)

	updateStringWithPointer(&s)
	fmt.Println("真正修改后的s:", s)
}

函数

函数的定义

package main

import "fmt"

/*
函数的定义:
func 函数名(参数1 类型, 参数2 类型) (返回值1 类型,返回值2 类型) {代码块}
func 函数名(参数2,参数2 类型) (返回值1,返回值2) {代码块}
func 函数名(参数2,参数2 类型) 类型 {代码块}
func 函数名(参数2,参数2 类型) {代码块}
func 函数名(参数1 类型, 参数2 类型) (类型, 类型) {代码块}
*/

func max(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func main() {
	fmt.Println(max(1, 3))
}
package main

import "fmt"

func intSum(a, b int) (sum int) {
	sum = a + b
	return
}

func main() {
	fmt.Println(intSum(1, 3))
}
package main

import "fmt"

func sortInt(a, b int) (min, max int) {
	if a < b {
		min = a
		max = b
	} else {
		min = b
		max = a
	}
	return
}

func main() {
	min, max := sortInt(99, 88)
	fmt.Println(min, max)
}

不定长参数

package main

import (
	"fmt"
	"strings"
)

// 接收不定长度参数的函数
func randomLength(s ...string) string {
	//接受到的多个参数会封装成一个切片
	fmt.Println(s)           //[hua zi]
	m := strings.Join(s, "") //huazi
	return m
}

func main() {
	m := randomLength("hua", "zi")
	fmt.Println(m)
}

递归函数

package main

import "fmt"

func factorial(n int) int {
	if n == 1 {
		return 1
	}
	return n * factorial(n-1)
}

func main() {
	res := factorial(5)
	fmt.Println(res) //5
}

递归函数使用场景:

  • 多级目录文件遍历
  • 多层数据结构数据查找
  • 网页菜单自动生成
  • 路由管理
  • 数值计算:斐波那契数列、阶乘、幂等

匿名函数

package main

import "fmt"

func main() {
	//定义匿名函数并调用
	func() {
		fmt.Println("这个匿名函数")
	}()
}

异常处理

go语言中有一种错误类型叫error

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	//案例:打开一个文件,文件存不存在呢
	f, err := ioutil.ReadFile("./file.txt") //会在同级目录中寻找file.txt这个文件
	if err != nil {
		//说明文件不存在,出现报错
		fmt.Println("打开文件失败:", err.Error())
	} else {
		fmt.Println("文件打开成功")
		fmt.Println(string(f))
	}
}

go语言中通过自定义err来实现异常处理

//自定义err的两种方式
package main

import (
	"errors"
	"fmt"
)

func main() {
    //自定义err的两种方式
	err1 := errors.New("这是一个自定义错误")
    //fmt.Println(err1.Error())
    fmt.Println(err1)   //要不要Error()都可以
	err2 := fmt.Errorf("这是一个自定义错误:%s,它是使用fmt生成的", "fmt定义的错误")
    //fmt.Println(err2.Error())
	fmt.Println(err2)
}
//案例:除法
package main

import (
	"errors"
	"fmt"
)

// 定义一个函数,来实现除法
func division(num1, num2 float64) (res float64, err error) {
	fmt.Println("需要计算的数字是:", num1, num2)
	if num2 == 0 {
		return 0, errors.New("输入的分母不能为0")
	} else {
		res = num1 / num2
		return res, nil
	}
}

func main() {
	res, err := division(2, 0)
	if err != nil {
		fmt.Println("计算错误", err.Error())
	} else {
		fmt.Println("计算结果", res)
	}
}

但是以上定义的err,如果出现了错误,程序也不会停止,会一直运行

那么如何在出现错误时终止程序呢

package main

import (
	"errors"
	"fmt"
	"time"
)

func connectDatabase(address string, port int) (string, error) {
	//如果address和port为空
	if address == "" || port == 0 {
		return "", errors.New("无法链接数据库")
	} else {
		return "数据库链接成功", nil
	}
}

func main() {
	// panic:可以在异常的时候让程序终止执行,退出程序。或者是程序所强依赖的基础组件不可用
	// 此时程序已经无法继续正常工作,此时可以使用panic抛出异常,并且把程序退出
	s, err := connectDatabase("", 0)
	for {
		time.Sleep(time.Second * 5)
		if err != nil {
			//说明无法链接数据库
			fmt.Println(err)
			panic(err) //此时就会退出程序
		} else {
			//说明链接成功
			fmt.Println(s)
		}
	}
}

那么终止程序后,我们需不需要做一些处理呢,比如终止程序后,我们需要发一些消息给前端

这时就可以使用到defer:是go语言中的一种延迟调用机制,defer里面的内容可以在函数return之前或者是程序panic之前执行

defer是可以有多个的,采用先进后出的机制;一般用于资源回收和数据返回,defer也可以用于异常时的恢复

defer后跟函数调用

package main

import (
	"errors"
	"fmt"
)

// 实现数据库的链接
func connectDatabase(address string, port int) (string, error) {
	// 如果address和port为空
	if address == "" || port == 0 {
		return "", errors.New("无法链接数据库")
	} else {
		return "数据库链接成功", nil
	}
}

// 返回数据给前端
func returnDataToFrontend(msg string) {
	fmt.Println("返回给前端的数据是:", msg)
}

func main() {
	msg := "返回给前端的数据"

	defer returnDataToFrontend(msg) // defer不会真正的执行

	_, err := connectDatabase("", 0)
	if err != nil {
		fmt.Println(err)
		// defer会在这一步执行
		panic(err)
	}
}

以上是终止程序后,将终止信息返回给管理员,那么我们又该如果将捕获到的错误信息进行相应的处理,从而让程序继续执行,不中断

package main

import "fmt"

func printSliceData(s []string) {
	//使用recover进行异常捕获
	defer func() {
		fmt.Println("程序执行失败,捕获异常")
		if err := recover(); err != nil {
			// recover是用来捕获panic的报错的,尝试恢复,防止程序异常退出
			fmt.Println("捕获一个错误:", err)
		}
	}()

	fmt.Println("切片的内容:", s)
	fmt.Println("切片的第三个值:", s[2]) //这里由于下标超出,程序会自己生成一个panic,从而终止程序
}

func main() {
	s := []string{"a", "b"}
	printSliceData(s)
}

Go自定义类型

结构体

go语言中的结构体是一种自定义数据类型,可以将不同类型的数据组合在一起形成一个单独的实体

package main

import "fmt"

/*
type 结构体名 struct {
    属性1 类型
    属性2 类型
}

var 变量名 结构体名{
    属性1: 值1
    属性2: 值2
}
*/

func main() {
	//定义一个名为People的结构体
	type People struct {
		name    string
		age     int
		address string
	}
	//先定义再赋值
	var p1 People
	p1.name = "华子"
	p1.age = 18
	p1.address = "陕西省汉中市"
	fmt.Println(p1) //{华子 18 陕西省汉中市}
	//直接声明
	p2 := People{
		name:    "huazi",
		age:     19,
		address: "陕西省汉中市",
	}
	fmt.Println(p2) //{huazi 19 陕西省汉中市}
	//第三种方式
	var p3 People = People{"hua", 20, "陕西省汉中市"}
	fmt.Println(p3) //{hua 20 陕西省汉中市}

	//使用
	fmt.Printf("名字:%s  年龄:%d\n", p2.name, p2.age)
	//修改值
	p2.name = "华"
	fmt.Printf("名字:%s  年龄:%d\n", p2.name, p2.age)
	//赋值
	p4 := p2
	fmt.Println(p4)
	//判断自定义变量是否相等
	fmt.Println(p4 == p2)
}

属性是这样定义的,那么方法该如何定义呢

package main

import "fmt"

//定义一个名为People的结构体
type People struct {
	name    string
	age     int
	address string
}

//定义结构体的方式函数
func (p *People) getInfo() string {
	return fmt.Sprintf("当前用户名:%s   年龄:%d    地址:%s\n",
		p.name, p.age, p.address)
}

func (p *People) Eat(food string) {
	fmt.Printf("%s今天吃了%s\n", p.name, food)
}

func main() {
	var p1 People = People{"华子", 18, "陕西省汉中市"}
	//调用方法:
	//变量.方法名()
	fmt.Println(p1.getInfo())
	p1.Eat("鸡公煲")
}

go变量大小写特性

getInfo小写开头的变量名,是私有元素,只能在本包内使用

Eat大写开头的变量名,是公开元素,可以被外部的包调用

指针类型和值类型的方法

  • 指针类型的方法
package main

import "fmt"

//定义一个名为People的结构体
type People struct {
	name    string
	age     int
	address string
}

/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*/

//定义结构体的方式函数(指针类型)
func (p *People) getInfo() string {
	p.age = 99
	return fmt.Sprintf("当前用户名:%s   年龄:%d    地址:%s\n",
		p.name, p.age, p.address)
}

func main() {
	var p1 People = People{"华子", 18, "陕西省汉中市"}
	//调用方法:
	//变量.方法名()
	fmt.Println(p1.getInfo())  //当前用户名:华子   年龄:99    地址:陕西省汉中市
	fmt.Println(p1)  //{华子 99 陕西省汉中市}
}
  • 值类型的方法
package main

import "fmt"

//定义一个名为People的结构体
type People struct {
	name    string
	age     int
	address string
}

/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*/

//定义结构体的方式函数(值类型)
func (p People) getInfo() string {
	p.age = 99
	return fmt.Sprintf("当前用户名:%s   年龄:%d    地址:%s\n",
		p.name, p.age, p.address)
}

func main() {
	var p1 People = People{"华子", 18, "陕西省汉中市"}
	//调用方法:
	//变量.方法名()
	fmt.Println(p1.getInfo()) //当前用户名:华子   年龄:99    地址:陕西省汉中市
	fmt.Println(p1)           //{华子 18 陕西省汉中市}
}

嵌套

  • 第一种嵌套方式
package main

import "fmt"

type Phone struct {
	mode  string
	price int
}

type People struct {
	name    string
	age     int
	address string
	mobile  Phone //People结构体中嵌套Phone
}

func (p *People) getInfo() string {
	return fmt.Sprintf("姓名:%s   手机:%s", p.name, p.mobile.mode)
}

func main() {
	var p1 People
	p1.name = "华子"
	p1.age = 18
	p1.address = "陕西省汉中市"
	p1.mobile.mode = "小米17"
	p1.mobile.price = 1999
	fmt.Println(p1.getInfo())
}
  • 第二种嵌套方式
package main

import "fmt"

type Phone struct {
	mode  string
	price int
}

type People struct {
	name    string
	age     int
	address string
}

type info struct {   //再写一个info结构体,将People和Phone合起来
	Phone
	People
}

func (p *info) getInfo() string {
	return fmt.Sprintf("姓名:%s   手机:%s", p.name, p.mode)
}

func main() {
	var p1 info
	p1.name = "华子"
	p1.age = 20
	p1.address = "陕西省汉中市"
	p1.mode = "小米"
	p1.price = 1999
	fmt.Println(p1.getInfo())
}

如果多个结构体上有相同的变量名,就不能直接进行赋值了

//如果多个结构体上有相同的变量名,就不能直接进行赋值了
package main

import "fmt"

type Phone struct {
	name  string
	price int
}

type People struct {
	name    string
	age     int
	address string
}

type info struct {  //再写一个info结构体,将People和Phone合起来
	Phone
	People
}

func (p *info) getInfo() string {
	return fmt.Sprintf("姓名:%s   手机:%s", p.People.name, p.Phone.name)
}

func main() {
	var p1 info
	p1.People.name = "华子"
	p1.age = 20
	p1.address = "陕西省汉中市"
	p1.Phone.name = "小米"
	p1.price = 1999
	fmt.Println(p1.getInfo())
}

interface接口类型

go语言的接口是一种类型,定义了一组方法的集合,但是接口又不需要去实现他们,这些方法可以被不同的类型实现,进而就是这个类型实现了这个接口。

在go语言中,接口是一个重要的概念,接口被广泛应用于许多标准库和框架中。通过接口,可以使不同的类型之间实现相同的行为,从而达到代码复用和扩展的目的,并且可以实现不同类型之间的无缝切换。

在这里插入图片描述

  • 不用接口之前
//对每个数据库的操作都要写不同的操作语句
package main

import "fmt"

//创建一个数据库的结构体,用来存放数据库的连接信息
type DBConfig struct {
	User     string
	Password string
	Host     string
	Port     int
	Database string
}

func main() {
	//声明一个mysql数据库实例
	db := DBConfig{"root", "password", "127.0.0.1", 3306, "interface_test"}
	fmt.Println("mysql数据库的配置:", db)
	//插入一条数据
	fmt.Println("在mysql中插入一条数据:db.row('insert xxx to user').Rows()")

	//换成pg
	//生成pg数据库的连接实例
	dbPg := DBConfig{"root", "password", "127.0.0.1", 3306, "interface_test"}
	fmt.Println("pg数据库的配置:", dbPg)
	//在pg中插入一条数据
	fmt.Println("在pg中插入一条数据:db.QueryRow('insert xxx to user')")
}
  • 使用接口之后
package main

import "fmt"

/*
type 接口名 interface {
	方法名(参数) 返回值
	方法名(参数) 返回值
	方法名(参数) 返回值
}
*/

type DBCommon interface {
	Insert(string) error
	Update(string) error
	Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
	User     string
	Password string
	Host     string
	Port     int
	Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
	config  DBConfig
	charSet string
}

func (m MySQL) Insert(data string) error {
	fmt.Println("插入数据到MySQL:", data)
	return nil
}

func (m MySQL) Update(data string) error {
	fmt.Println("更新数据到MySQL:", data)
	return nil
}

func (m MySQL) Delete(data string) error {
	fmt.Println("删除数据到MySQL:", data)
	return nil
}

func main() {
	db := DBConfig{"root", "password", "127.0.0.1", 3306, "interface_test"}
	//声明一个接口的变量
	var dbCommonInterface DBCommon
	var m MySQL
	m.config = db
	m.charSet = "utf-8"
	dbCommonInterface = m  //将结构体变量赋值给接口变量
	dbCommonInterface.Insert("insert")  //调用接口中的定义的函数
	dbCommonInterface.Update("update")
	dbCommonInterface.Delete("delete")
}
package main

import "fmt"

/*
type 接口名 interface {
	方法名(参数) 返回值
	方法名(参数) 返回值
	方法名(参数) 返回值
}
*/

type DBCommon interface {
	Insert(string) error
	Update(string) error
	Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
	User     string
	Password string
	Host     string
	Port     int
	Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
	config  DBConfig
	charSet string
}

func (m MySQL) Insert(data string) error {
	fmt.Println("插入数据到MySQL:", data)
	return nil
}

func (m MySQL) Update(data string) error {
	fmt.Println("更新数据到MySQL:", data)
	return nil
}

func (m MySQL) Delete(data string) error {
	fmt.Println("删除数据到MySQL:", data)
	return nil
}

type PostgreSQL struct {
	config  DBConfig
	charSet string
}

func (m PostgreSQL) Insert(data string) error {
	fmt.Println("插入数据到PostgreSQL:", data)
	return nil
}

func (m PostgreSQL) Update(data string) error {
	fmt.Println("更新数据到PostgreSQL:", data)
	return nil
}

func (m PostgreSQL) Delete(data string) error {
	fmt.Println("删除数据到PostgreSQL:", data)
	return nil
}

func main() {
	db := DBConfig{"root", "password", "127.0.0.1", 3306, "interface_test"}
	//声明一个接口的变量
	var dbCommonInterface DBCommon
	//var m MySQL
	var m PostgreSQL
	m.config = db
	m.charSet = "utf-8"
	dbCommonInterface = m
	dbCommonInterface.Insert("insert")
	dbCommonInterface.Update("update")
	dbCommonInterface.Delete("delete")
}
package main

import "fmt"

/*
type 接口名 interface {
	方法名(参数) 返回值
	方法名(参数) 返回值
	方法名(参数) 返回值
}
*/

type DBCommon interface {
	Insert(string) error
	Update(string) error
	Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
	User     string
	Password string
	Host     string
	Port     int
	Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
	config  DBConfig
	charSet string
}

func (m MySQL) Insert(data string) error {
	fmt.Println("插入数据到MySQL:", data)
	return nil
}

func (m MySQL) Update(data string) error {
	fmt.Println("更新数据到MySQL:", data)
	return nil
}

func (m MySQL) Delete(data string) error {
	fmt.Println("删除数据到MySQL:", data)
	return nil
}

type PostgreSQL struct {
	config  DBConfig
	charSet string
}

func (m PostgreSQL) Insert(data string) error {
	fmt.Println("插入数据到PostgreSQL:", data)
	return nil
}

func (m PostgreSQL) Update(data string) error {
	fmt.Println("更新数据到PostgreSQL:", data)
	return nil
}

func (m PostgreSQL) Delete(data string) error {
	fmt.Println("删除数据到PostgreSQL:", data)
	return nil
}

type sqlServer struct {
	config  DBConfig
	charSet string
}

func (m sqlServer) Insert(data string) error {
	fmt.Println("插入数据到sqlServer:", data)
	return nil
}

func (m sqlServer) Update(data string) error {
	fmt.Println("更新数据到sqlServer:", data)
	return nil
}

func (m sqlServer) Delete(data string) error {
	fmt.Println("删除数据到sqlServer:", data)
	return nil
}

func main() {
	dbType := "sqlserver"

	//声明一个接口的变量
	var dbCommonInterface DBCommon
	if dbType == "mysql" {
		var m MySQL
		dbCommonInterface = m
	} else if dbType == "PostgreSQL" {
		var pg PostgreSQL
		dbCommonInterface = pg
	} else {
		var sqlS sqlServer
		dbCommonInterface = sqlS
	}
	dbCommonInterface.Insert("insert")
	dbCommonInterface.Update("update")
	dbCommonInterface.Delete("delete")
}

空接口

  • 方法1
package main

import "fmt"

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

//定义一个空接口
type EmptyInterface interface{}

func main() {
	var ei EmptyInterface //ei是一个空接口类型的变量,可以接受任何类型的赋值
	s1 := "这是一个字符串"
	i1 := 72578
	ei = s1
	fmt.Println(ei)
	ei = i1
	fmt.Println(ei)
}
  • 方法2
package main

import "fmt"

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

func main() {
	s1 := "这是一个字符串"
	i1 := 18
	//定义空接口方法2
	var ei1 interface{}
	ei1 = s1
	fmt.Println(ei1)
	ei1 = i1
	fmt.Println(ei1)
}
package main

import "fmt"

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

func main() {
	//map记录联系方式:手机号(int)  座机号(010-123-789)string类型
	contacts := make(map[string]interface{}) //在map中定义空接口可以接受不同类型的值
	contacts["huazi"] = 13289446832
	contacts["dot"] = "010-123-789"
	fmt.Println(contacts)
}

在这里插入图片描述

接口类型断言和类型判断

package main

import "fmt"

/*
类型断言:大致知道了接口可能是某种类型,然后使用t,ok := 变量.(类型)
类型判断:switch t := 变量.(type){}
*/

func dealData(data interface{}) {
	t, ok := data.(string) //如果data是string类型,则返回true给ok,t接受data的值,否则t接受空值
	if ok {
		fmt.Println("当前类型为string,变量的值是:", t)
	} else {
		fmt.Println("data不是字符串")
		fmt.Println("当前t的值:", t)
	}
}

func main() {
	s := "这是一个字符串"
	dealData(s)
	i := 123456
	dealData(i)
}
package main

import "fmt"

func getType(i interface{}) {
	switch t := i.(type) {
	case int:
		fmt.Println("当前值为int类型:", t)
	case string:
		fmt.Println("当前值为string类型:", t)
	case bool:
		fmt.Println("当前值为bool类型:", t)
	default:
		fmt.Println("当前类型不在处理范围")
	}
}

func main() {
	s := "这个一个字符串"
	getType(s)
	i := 123
	getType(i)
	var emtry interface{}
	getType(emtry)

}

接口嵌套和继承

package main

import "fmt"

type Generic_i interface {
	Login()
	LogOut()
}

type VIP_i interface {
	Consult()
}

type User_i interface {
	Generic_i
}

type VIPUser_i interface {
	Generic_i
	VIP_i
}

type Userordinary_s struct {
	Name string
}

func (u Userordinary_s) Login() {
	fmt.Println("用户已登录:", u.Name)
}
func (u Userordinary_s) LogOut() {
	fmt.Println("用户已退出:", u.Name)
}

type Uservip_s struct {
	Name string
}

func (u Uservip_s) Login() {
	fmt.Println("vip用户已登录:", u.Name)
}
func (u Uservip_s) LogOut() {
	fmt.Println("vip用户已退出:", u.Name)
}
func (u Uservip_s) Consult() {
	fmt.Println("vip用户可以进行咨询:", u.Name)
}

func main() {
	var userinterface User_i
	u := Userordinary_s{
		Name: "华子",
	}
	userinterface = u
	userinterface.Login()
	userinterface.LogOut()

	var vipuserinterface VIPUser_i
	vipu := Uservip_s{
		Name: "戈兄",
	}
	vipuserinterface = vipu
	vipuserinterface.Login()
	vipuserinterface.LogOut()
	vipuserinterface.Consult()
}

go相关命令
//对go源码进行编译,生成.exe文件
go build go文件名
//直接运行go源码(生成.exe文件执行后,又删除.exe文件)
go run go文件名
go中的package和import
/package:用来声明这个文件是属于哪个包的/
package main

/import:导入包,对包中的函数进行引用和复用/
import “fmt”

//main函数是程序的入口
func main() {
fmt.Println(“hello world”) //自带换行
fmt.Printf(“占位符格式化打印,传递过来的值,这个值用 %s 占位”, “运维开发”)
fmt.Print(“hello world”) //不换行
fmt.Println(“hello”, “world”) //类似于python的拼接
fmtEnv := fmt.Sprintf(“你好%s,大小%d”, “hello”, 5) //将拼接后的字符串赋值给变量
fmt.Println(fmtEnv) //打印变量
fmt.Println(3.1415926) //打印整数
}
什么是包:可以理解为go源码的集合,也是一种比较高级的代码复用方案

我们可以把一些复用的代码或功能函数封装在一起,然后形成一个包,可以被其他包或go文件进行引用
什么是main包:main是一个特殊的包,一个可执行的程序有且只有一个main包

什么是main函数:main函数是整个程序的入口,如果一个程序没有main函数是无法正常执行程序的

花括号:表示一个代码块,花括号内的代码属于同一个块内,也可以说属于同一个域内

函数使用func进行声明

人机交互
package main

import “fmt”

func main() {
//方式1:fmt.Scanln(指针)
var name string
var age byte
var salary float32
var isPass bool
//当程序执行到fmt.Scanln(&name),程序会停止在这里,等待用户输入,并回车
fmt.Printf(“请输入姓名:”)
fmt.Scanln(&name)

fmt.Printf("请输入年龄:")
fmt.Scanln(&age)

fmt.Printf("请输入薪水:")
fmt.Scanln(&salary)

fmt.Printf("是否通过考试(true or flase):")
fmt.Scanln(&isPass)
fmt.Printf("名字:%v\n年龄:%v\n薪水:%v\n是否通过考试:%v", name, age, salary, isPass)

}
package main

import “fmt”

func main() {
//方式2:fmt.Scanf()
var name string
var age byte
var salary float32
var isPass bool
fmt.Printf(“输入姓名,年龄,薪水,是否通过考试:”)
fmt.Scanf(“%s %d %f %t”, &name, &age, &salary, &isPass)
fmt.Printf(“名字:%v\n年龄:%v\n薪水:%v\n是否通过考试:%v”, name, age, salary, isPass)
}
变量
在这里插入图片描述

package main

import “fmt”
//函数外赋值
var address string = “172.25.254.80”

add := “gaga” //会报错
func main() {
//var 变量名 变量类型
var name1 string //先定义
name1 = “huazi” //再赋值
fmt.Println(name1)

//一次性定义多个相同类型的变量
var name2, user string = "hua", "huazi" 
fmt.Println(name2, user)

//一次性定义多个不同类型的变量
var (
	age1  int    = 18
	name3 string = "huazi"
)
fmt.Println(name3, age1)

//当省略类型后,go会自动判断,自动转换为强数据类型
var (
	name4 = "huazi"
	age2  = 18
)
fmt.Println(name4, age2)

//当省略了var,只能再函数内使用,要用:= ,称之为语法糖
//相当于var变成了:
name5 := "huazi"   //我们成为语法糖写法
age3 := 18
fmt.Println(name5, age3)

//交换变量的值
name6 := "hua"
name7 := "huazi"
name6, name7 = name7, name6 
fmt.Println(name6, name7)

//reflect.TypeOf(变量名)  打印变量的类型或者使用%T来表示类型
fmt.Println(reflect.TypeOf(name6))

}
在函数外定义并赋值的变量是包级别的变量,这种变量可以不对其进行使用。但是在函数中定义的变量必须得到使用

函数外不能使用语法糖来定义变量

常量
package main

import (
“fmt”
)

const ADDRESS string = “172.25.254.80”

func main() {
fmt.Println(ADDRESS)

//一次性定义多个相同类型的变量
const name1, name2 string = "hua", "huazi"
fmt.Println(name1, name2)

//一次性定义多个不同类型的常量
const (
	name3 string = "yao"
	age int = 18
)
fmt.Println(name3, age)

//常量可以省略类型,但是不能省略const
const (
	name4 = "ze"
	age1 = 18
)
fmt.Println(name4, age1)

age1 = 20   //会报错,因为常量不能修改

const (
	num1 int = 1
	num2
	num3
	str1 string = "hua"
	str2
	str3
)
fmt.Println(num1, num2, num3)  //1 1 1
fmt.Println(str1, str2, str3)  //hua hua hua

//枚举(const+iota),iota的基数是0
	const (
	e1 int = (1 + iota) * 10
	e2
	e3
)
fmt.Println(e1, e2, e3)   //10 20 30

}
常量在函数内外都是可以不进行使用的

%v
在 Go 语言中,%v 是一个通用的格式化动词(format verb),用于 fmt 包中的格式化函数,如 fmt.Printf、fmt.Sprintf 和 fmt.Fprintf 等。%v 可以用于不同类型的值,并会根据值的类型输出其默认的字符串表示。

以下是一些示例,展示了 %v 如何处理不同类型的数据:

整数:

fmt.Printf(“%v\n”, 42) // 输出: 42
浮点数:

fmt.Printf(“%v\n”, 3.14) // 输出: 3.14
字符串:

fmt.Printf(“%v\n”, “hello”) // 输出: hello
布尔值:

fmt.Printf(“%v\n”, true) // 输出: true
指针:

var p *int = &age
fmt.Printf(“%v\n”, p) // 输出: 0xc0000180b0(或类似的内存地址)
结构体:

type Person struct {
Name string
Age int
}

p := Person{Name: “Alice”, Age: 30}
fmt.Printf(“%v\n”, p) // 输出: {Alice 30}
切片:

slice := []int{1, 2, 3}
fmt.Printf(“%v\n”, slice) // 输出: [1 2 3]
映射:

m := map[string]int{“a”: 1, “b”: 2}
fmt.Printf(“%v\n”, m) // 输出: map[a:1 b:2]
接口:

var i interface{} = “world”
fmt.Printf(“%v\n”, i) // 输出: world
使用 %v 时,Go会根据值的实际类型选择适当的字符串表示,因此它是一个方便且通用的格式化动词。然而,对于某些特定类型,你可能希望使用更具体的格式化动词以获得更精细的控制。例如,对于整数可以使用 %d,对于浮点数可以使用 %f,对于字符串可以使用 %s 等等。

作用域
在go中使用{}来定义作用域的范围
使用原则:子语句块中可以使用父语句块中的标识符,父不能使用子的
package main

import (
“fmt”
)

func main() {
num1 := 1
{
num2 := 2
fmt.Println(num1)
fmt.Println(num2)
}
//fmt.Println(num2) //报错
}
package main

import (
“fmt”
)

func printAll() {
fmt.Println(“今天是个好日子”)
fmt.Println(“hello world”)
num1 := 1
fmt.Println(num1)
}
func main() {
printAll() //调用函数
//fmt.Println(num1) 报错
}
运算符
算术运算
package main

import “fmt”

//定义参数
func Calculate(num1 int, num2 int) {
fmt.Printf(“num1+num2=%d\n”, num1+num2)
fmt.Printf(“num1-num2=%d\n”, num1-num2)
fmt.Printf("num1num2=%d\n", num1num2)
fmt.Printf(“num1/num2=%d\n”, num1/num2) //取整
fmt.Printf(“num1取余num2=%d\n”, num1%num2)
}

func main() {
num1 := 1
num2 := 2
Calculate(num1, num2) //值传递
}
字符串拼接
package main

import “fmt”

func stringCalculate(str1 string, str2 string) {
fmt.Printf(“str1+str2=%s\n”, str1+str2)
word := fmt.Sprintf(“str1+str2=%s”, str1+str2)
fmt.Println(word)
}

func main() {
str1 := “hello”
str2 := “world”
stringCalculate(str1, str2)
}
//自增自减
p1 := 8
p1++
fmt.Println(“p1 =”, p1)
p1–
fmt.Println(“p1 =”, p1)
package main

import “fmt”

func main() {
a := 3
b := 2
fmt.Println(a / b) //取整 1
fmt.Println(float64(a) / float64(b)) // 1.5小数运算
}
浮点数不能和整数一起运算

float32类型的和float64类型的不能运算

int类型和float类型
package main

import (
“fmt”
“math”
“reflect”
)

func main() {
// 数值类型:int int8 int16 int32 int64 uint
// int: 正负数 uint:不带符号的数字 // int
defaultIntType := 1
fmt.Println(“默认的数值类型是:”, reflect.TypeOf(defaultIntType))
// int和操作系统是有关系的
// 64位的,int64 32位的 int32
var int64Num int64 = 1
fmt.Println(“int64Num的数值类型是:”, reflect.TypeOf(int64Num))
var uintNum uint = 1
fmt.Println(“uintNum的数值类型是:”, reflect.TypeOf(uintNum))
fmt.Println(“int的取值范围:”, math.MinInt, math.MaxInt)
fmt.Println(“uint的取值范围:”, uint(math.MaxUint))
fmt.Println(18446744073709551615 > 9223372036854775807)
// float float32和float64
var floatNum1 float64 = 3.14
var floatNum2 float32 = 3.15
// floatSum := floatNum1 + floatNum2
fmt.Println(floatNum1, floatNum2)
}
关系与逻辑运算符
package main

import (
“fmt”
“reflect”
)

func main() {
// 大于, 小于
fmt.Println(727585 > 727588) // false
fmt.Println(727585 < 727588) // true
// 是否相等, =和==的区别
fmt.Println(“a” == “b”) // false
fmt.Println(3.14 == 3.14)

s1 := "dukuan"
s2 := "dotbalo"
// xxx := s1 == s2
fmt.Println("s1和s2相等: ", s1 == s2)
fmt.Println("s1和s2不相等: ", s1 != s2)
fmt.Println("s1 > s2:", s1 > s2)
fmt.Println("s2 > s1:", s2 > s1) //字符串是可以比较大小的, ASCII
// 逻辑与和逻辑或  && ||
n1 := 1
n2 := 1
n3 := 2
// 与: 所有的表达式都为true,最终的结果就为true
fmt.Println(n1 == n2 && n2 == n3) // true false => false
// 或:任意一个为true,最终结果就为true
fmt.Println(n1 == n2 || reflect.TypeOf(n3).Kind() == reflect.String)

}
if-else
package main

import (
“fmt”
)

func printWeather(weather string) {
if weather == “sunny” {
fmt.Println(“今天是晴天”)
} else if weather == “rain” {
fmt.Println(“今天是雨天”)
} else {
fmt.Println(“今天气候不明”)
}
}

func main() {
weather := “rain”
printWeather(weather)
}
if的特殊用法
package main

import “fmt”

func backBool() bool {
return true
}

func main() {
a := false
if res := backBool(); res != a { //在判断前,先进行运算
fmt.Println(“true”)
} else {
fmt.Println(“false”)
}
}
switch
package main

import (
“fmt”
)

func printScore(score int) {
sc := score / 10
switch sc {
case 10, 9:
fmt.Println(“优秀”)
break
case 8:
fmt.Println(“良好”)
case 7:
fmt.Println(“中等”)
case 6:
fmt.Println(“及格”)
default:
fmt.Println(“不及格”)
}
}

func main() {
printScore(66)
}
break默认可以省略不写

for
package main

import (
“fmt”
“time”
)

func main() {
count := 0 //记录偶数的个数
for num := 0; num < 100; num++ {
if num%2 == 0 {
fmt.Println(“发现一个偶数:”, num)
count++
}
time.Sleep(time.Second) //停顿1秒,second是秒的意思
}
fmt.Printf(“一共有%d个偶数”, count)
}
for实现死循环

package main

import (
“fmt”
“time”
)

func main() {
for {
timeNow := time.Now() //获取当前时间
// 2006-01-02 15:04:05 go语言的诞生时间
fmt.Println(“当前时间是:”, timeNow.Format(“2006-01-02 15:04:05”))
time.Sleep(time.Second * 3) //停顿3秒
}
}
break与continue
package main

import (
“fmt”
)

func main() {
temp := 20
count := 0
for {
if count == 20 {
fmt.Println(“恭喜你找到了”, temp)
break
} else {
count++
}
}
}
package main

import (
“fmt”
“time”
)

func main() {
for i := 0; i < 100; i++ {
if i == 88 {
fmt.Println(“我找到了88”)
break
}
fmt.Println(“现在的数值是:”, i)
}
time.Sleep(time.Second * 3)
for i := 0; i < 50; i++ {
if i == 33 {
fmt.Println(“我找到了33”)
continue
}
fmt.Println(“现在的数值是:”, i)
}
}
数组
package main

import “fmt”

func main() {
//数组定义:一组具有相同类型并且长度固定的一个数据集合
//var 数组名 = [长度]类型{value1,value2}
var name = [3]string{“小明”, “华子”, “戈兄”}
fmt.Println(name) //[小明 华子 戈兄]
fmt.Println(name[0])
//修改
name[0] = “小华”
fmt.Println(name)
//for循环访问
for i := 0; i < 3; i++ {
fmt.Println(name[i])
}
//求数组的长度
length := len(name)
fmt.Println(length)

//range使用
for i, v := range name {
	fmt.Println(i, v)
}

//自动推断长度
array3 := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(len(array3))

}
切片
package main

import “fmt”

func main() {
// 切片:切片的长度是不固定的,可以扩容
// var 切片名称 = []切片类型{value1, value2…}
var slice1 []int //先定义切片
fmt.Println(slice1) // []
// 切片默认的两个属性:1.切片的长度,表示切片中有多少个元素 2.切片的容量,表示切片中最大可以放多少个元素
fmt.Println(“切片的默认长度是:”, len(slice1)) // 0
fmt.Println(“切片的默认容量:”, cap(slice1)) // 0

// 添加元素
slice1 = append(slice1, 1, 2, 3, 4)
fmt.Println(slice1)             // [1 2 3 4]
fmt.Println("长度:", len(slice1)) // 4
fmt.Println("容量:", cap(slice1)) // 4
// 修改数据
slice1[0] = 88
fmt.Println(slice1) //  [88 2 3 4]

//定义切片并初始化
var slice2 = []string{"切片1", "切片2", "切片3"}
fmt.Println(slice2)                //  [0 0 0 0 0]
fmt.Println("切片的长度:", len(slice2)) // 3
fmt.Println("切片的容量:", cap(slice2)) // 3
slice2 = append(slice2, "切片4", "切片5")
fmt.Println(slice2) //  [0 0 0 0 0]

//第二种声明方式,指定长度
slice3 := make([]int, 5, 10)         //5个长度,10个容量
fmt.Println(slice3)                  // [0 0 0 0 0]
fmt.Println("切片的默认长度:", len(slice3)) // 5
fmt.Println("切片的默认容量:", cap(slice3)) // 10
slice3 = append(slice3, 1, 2, 3)
fmt.Println(slice3) //  [0 0 0 0 0 1 2 3]

slice4 := make([]string, 3, 5)
fmt.Println(slice4) // 默认初始化一个空格
slice4 = append(slice4, "hua")
fmt.Println(slice4)

// for循环遍历
for i, v := range slice2 {
	fmt.Println(i, v)
}

}
数组和切片在声明时的区别:数组有长度,切片没有长度

切片截取和元素删除
package main

import “fmt”

func main() {
var s = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(“最初的数据是:”, s)
fmt.Println(“前4位数据:”, s[0:4]) //包头不包尾
fmt.Println(“从第5个数据开始:”, s[4:])

//删除一个元素:go语言中删除切片中的元素是通过截取的方式实现的
s = s[1:] // 删除第一个元素
fmt.Println(s)
s = s[:len(s)-1] // 删除最后一个元素
fmt.Println(s)
s = append(s[:2], s[3:]...) // 删除第3个元素
fmt.Println(s)

}
深拷贝与浅拷贝
package main

import “fmt”

func main() {
str1 := “huazi”
str2 := str1 //深拷贝
fmt.Println(str1, str2) //huazi huazi
str2 = “hua”
fmt.Println(str1, str2) //huazi hua

//定义一个切片
slice1 := []int{1, 2, 3, 4, 5, 6}
slice2 := slice1 //浅拷贝
fmt.Println(slice1, slice2)  //[1 2 3 4 5 6] [1 2 3 4 5 6]
slice2[0] = 88
fmt.Println(slice1, slice2)   //[88 2 3 4 5 6] [88 2 3 4 5 6]

}
深拷贝:复制一个变量时,会创建一个全新的变量,并且将原始数据复制给新变量,新变量在内存中会是一个新的地址,并且两个变量修改时不会影响其他变量

浅拷贝:复制一个变量时,也会创建一个新的变量,但是两个变量共享底层的数据,也就是新旧变量会指向同一个数据的内存地址,实际上算是引用同一个数据,也就是意味着任意一个变量发生变更,其他变量也会被修改

值类型:复制变量的时候是深拷贝,值类型包括(int,float,string,struct,array,bool)

引用类型:复制变量的时候是浅拷贝,引用类型包括:(slice,map,channel,interface)

package main

import (
“fmt”
“unsafe”
)

func main() {
str1 := “huazi”
str2 := str1 //深拷贝
fmt.Println(str1, str2)
str2 = “hua”
fmt.Println(str1, str2)

//定义一个切片
slice1 := []int{1, 2, 3, 4, 5, 6}
//如何对切片进行深拷贝呢
slice2 := make([]int, len(slice1), cap(slice1))
copy(slice2, slice1) //深拷贝
slice2[0] = 88       //对slice2的修改不影响slice1
fmt.Println(slice1, slice2)

//打印内存地址
fmt.Println("slice1的内存地址", unsafe.Pointer(&slice1))       //1
fmt.Println("slice1[0]的内存地址", unsafe.Pointer(&slice1[0])) //2
fmt.Println("slice2的内存地址", unsafe.Pointer(&slice2))       //3
fmt.Println("slice2[0]的内存地址", unsafe.Pointer(&slice2[0])) //4

}
map映射
package main

import “fmt”

func main() {
// var map名 = map[type]type{key1:value1, key2:value2…}
teacherAge := make(map[string]int)
fmt.Println(“map的初始化值”, teacherAge) //map[]
teacherAge[“huazi”] = 18
teacherAge[“xiaoming”] = 20
teacherAge[“huazi”] = 22
fmt.Println(“赋值后的值”, teacherAge) //map[huazi:22 xiaoming:20]

//在声明变量的时候直接进行赋值操作
teacherAge1 := map[string]int{
	"d1": 2,
	"d2": 3,
}
fmt.Println(teacherAge1) //map[d1:2 d2:3]

//先用var声明
var teacherAddress map[string]string
//再用make声明内存空间
teacherAddress = make(map[string]string)
teacherAddress["huazi"] = "洋县"
teacherAddress["hua"] = "汉川"
fmt.Println(teacherAddress) //map[hua:汉川 huazi:洋县]

//访问
fmt.Println("huazi老师的地址", teacherAddress["huazi"])

searchName := "hua"
fmt.Printf("%s老师的地址:%s\n", searchName, teacherAddress[searchName])

//for range
for k, v := range teacherAddress {
	fmt.Printf("%s老师的地址:%s\n", k, v)
}
fmt.Println("取一个不存在的值:", teacherAddress["hhhh"]) //空字符串

//map中的ok判断
value, ok := teacherAddress["hua"] //如果hua这个键不存在返回false,存在返回true
if ok {
	fmt.Printf("能查看到hua的地址:%s\n", value)
} else {
	fmt.Printf("不能查到hua的地址\n")
}

// 修改值
teacherAddress["hua"] = "北京"
fmt.Println("修改后的值:", teacherAddress["hua"])

// 删除值
delete(teacherAddress, "huazi")
fmt.Println("删除后的map:", teacherAddress)

}
切片中嵌套map对象
var slice = []map[type]type
package main

import “fmt”

func main() {
order1 := map[string]int{
“宫保鸡丁”: 99,
“糖酸鱼”: 88,
}
order2 := map[string]int{
“回锅肉”: 66,
“鱼香肉丝”: 89,
}
order3 := map[string]int{
“奶茶”: 18,
“可乐”: 3,
}
var menu []map[string]int //map[string]int是一个整体
menu = append(menu, order1, order2, order3)
fmt.Println(menu) //[map[宫保鸡丁:99 糖酸鱼:88] map[回锅肉:66 鱼香肉丝:89] map[可乐:3 奶茶:18]]
for i, v := range menu { //i是下标,v是map对象
fmt.Printf(“第%d天的菜单是:\n”, i+1)
for name, price := range v {
fmt.Printf(“\t菜名:%s,价格:%d\n”, name, price)
}
}
}
map对象嵌套map对象
var map11 = map[type]map[type]type
package main

import (
“fmt”
)

func main() {
//map对象嵌套map对象
// map[string]map[string]string
address1 := map[string]string{
“汉中市”: “洋县”,
“宝鸡市”: “凤县”,
}
address2 := map[string]string{
“武功市”: “好县”,
“花市”: “中等县”,
}
var country map[string]map[string]string
country = make(map[string]map[string]string)
country[“陕西省”] = address1
country[“浙江省”] = address2
fmt.Println(country)
for province, city_map := range country {
fmt.Printf(“%s:\n”, province)
for city, county := range city_map {
fmt.Printf(“\t%s %s\n”, city, county)
}
}
}
类型转换
package main

import (
“fmt”
“math”
)

// 参数类型为float64,返回值类型为float64
func area(r float64) float64 {
s := math.Pi * r * r
return s
}

func main() {
r := 5 //此时r默认为int类型
s := area(float64®) //需要使用float64()把int转为float64
fmt.Println(“面积是:”, s)
}
在这里插入图片描述

package main

import (
“fmt”
“reflect”
“strconv”
)

func main() {
i1 := 10
//将int类型转为string类型
str1 := strconv.Itoa(i1)
fmt.Println(str1, reflect.TypeOf(str1))

str2 := "1001"
//将string类型转为int类型
i2, _ := strconv.Atoi(str2) //通过_来规避掉函数的返回值
fmt.Println(i2, reflect.TypeOf(i2))

// str3 := "100"
str3 := "100a"
i3, err := strconv.Atoi(str3) //如果err有值,则转换失败,err为nil则转换成功
if err != nil {
	// 转换失败
	fmt.Println(err)
	fmt.Println("转换失败,当前值不能转换为数值")
} else {
	//转换成功
	fmt.Println(err)
	fmt.Println("转换成功", i3)
}

}
package main

import (
“fmt”
“strconv”
)

func main() {
//将0 1 f t float true Float True FLOAT TRUE等布尔型字符串转为bool类型
str1 := “t”
bool1, _ := strconv.ParseBool(str1)
fmt.Println(“转换后的布尔值:”, bool1)
}
字符串方法
package main

import (
“fmt”
“strings”
)

func main() {
// 字符串的定义
// "" // "\t \n"
s := “\t\txxx\n”
fmt.Println(“双引号字符串:”, s)
s2 := \t\txxx\n
fmt.Println(“反引号字符串:”, s2)
s3 := 我是杜宽 我主要教授的课程是: 云原生系列,k8s,go,python
fmt.Println(“多行字符串:”, s3)
// 字符长度的计算
s4 := “dukuan”
s5 := “杜宽” //中文占用3个字符
s4Length := len(s4)
s5Length := len(s5)
fmt.Println(s4Length, s5Length)
// 字符串的截取 , 一般
// s6 := s4[2]
fmt.Println(“前两位:”, s4[:2])
s7 := “dukuan”
// 大小写转换, 一般
fmt.Println(“转成大写:”, strings.ToUpper(s7))
fmt.Println(“首字母大写”, strings.Title(s7))
s8 := “dUKUan”
fmt.Println(“转成小写:”, strings.ToLower(s8))
// 字符串是否包含某个元素 ,还行
fmt.Println(“查看字符串是否包含uk这个元素:”, strings.Contains(s7, “uk”))
fmt.Println(“查看字符串是否包含任意一个字符:”, strings.ContainsAny(s7, “uw”))
// 忽略大小写进行比较
fmt.Println(“忽略大小写比较:”, strings.EqualFold(s7, s8))
// 判断字符串中某个元素有多个个
s9 := “dukuan and dot is me, my age is 18”
fmt.Println(“u在字符串中出现了:”, strings.Count(s9, “u”))
// 字符串拆分 //很多
s9Split := strings.Split(s9, “,”)
fmt.Println(“使用逗号拆分字符串:”, s9Split)
fmt.Println(“拆分后的切片的第一个数据:”, s9Split[0])
s9SplitAfter := strings.SplitAfter(s9, “,”)
fmt.Println(“使用逗号拆分字符串,并且保留逗号:”, s9SplitAfter)
// 字符串拼接 //很多
slice1 := []string{“dot”, “balo”, “du”, “kuan”}
fmt.Println(“拼接字符串:”, strings.Join(slice1, " “))
// 是否是某个元素开头的 ,还行
s10 := “我是一个中国人,我非常热爱中国”
fmt.Println(“字符串是以 ‘我’ 开头的:”, strings.HasPrefix(s10, “我”))
// 此处的视频出现错误,应该是HasSuffix
fmt.Println(“字符串是以 爱 结尾的:”, strings.HasSuffix(s10, “爱”))
// 重复字符串
fmt.Println(“打印五个我:”, strings.Repeat(“我”, 5))
// 字符串替换 ,还行
s11 := “dsad3afd3rq3adawdwarq3a”
fmt.Println(“把3替换为dukuan:”, strings.ReplaceAll(s11, “3”, “dukuan”))
fmt.Println(“把3替换为杜宽:”, strings.Replace(s11, “3”, “杜宽”, 1)) // 0替换所有
// trim 字符串修剪 ,很多
s12 := " dukuan ,”
fmt.Println(“去掉字符串的前后空格:”, strings.Trim(s12, “,”))
}
指针和内存地址
package main

import “fmt”

func updateString(s string) {
s = “这是一个新值”
}
func updateStringWithPointer(s *string) {
*s = “这是一个新值”
}

func main() {
var s string
s = “这是一个字符串”
fmt.Println(“变量s的内存地址是:”, &s)
// sp: 指针
// 内存地址: 通过&符号进行取值
sp := &s
fmt.Println(“指针sp:”, sp)
var sp2 *string
fmt.Println(“指针sp2:”, sp2) // 指针未进行赋值的时候为nil
sp2 = &s
fmt.Println(“指针sp2:”, sp2)
// 通过指针获取内存地址的值
fmt.Println(“指针对应内存地址的值:”, *sp2)

updateString(s)
fmt.Println("修改后的s:", s)

updateStringWithPointer(&s)
fmt.Println("真正修改后的s:", s)

}
函数
函数的定义
package main

import “fmt”

/*
函数的定义:
func 函数名(参数1 类型, 参数2 类型) (返回值1 类型,返回值2 类型) {代码块}
func 函数名(参数2,参数2 类型) (返回值1,返回值2) {代码块}
func 函数名(参数2,参数2 类型) 类型 {代码块}
func 函数名(参数2,参数2 类型) {代码块}
func 函数名(参数1 类型, 参数2 类型) (类型, 类型) {代码块}
*/

func max(a, b int) int {
if a > b {
return a
} else {
return b
}
}

func main() {
fmt.Println(max(1, 3))
}
package main

import “fmt”

func intSum(a, b int) (sum int) {
sum = a + b
return
}

func main() {
fmt.Println(intSum(1, 3))
}
package main

import “fmt”

func sortInt(a, b int) (min, max int) {
if a < b {
min = a
max = b
} else {
min = b
max = a
}
return
}

func main() {
min, max := sortInt(99, 88)
fmt.Println(min, max)
}
不定长参数
package main

import (
“fmt”
“strings”
)

// 接收不定长度参数的函数
func randomLength(s …string) string {
//接受到的多个参数会封装成一个切片
fmt.Println(s) //[hua zi]
m := strings.Join(s, “”) //huazi
return m
}

func main() {
m := randomLength(“hua”, “zi”)
fmt.Println(m)
}
递归函数
package main

import “fmt”

func factorial(n int) int {
if n == 1 {
return 1
}
return n * factorial(n-1)
}

func main() {
res := factorial(5)
fmt.Println(res) //5
}
递归函数使用场景:

多级目录文件遍历
多层数据结构数据查找
网页菜单自动生成
路由管理
数值计算:斐波那契数列、阶乘、幂等
匿名函数
package main

import “fmt”

func main() {
//定义匿名函数并调用
func() {
fmt.Println(“这个匿名函数”)
}()
}
异常处理
go语言中有一种错误类型叫error

package main

import (
“fmt”
“io/ioutil”
)

func main() {
//案例:打开一个文件,文件存不存在呢
f, err := ioutil.ReadFile(“./file.txt”) //会在同级目录中寻找file.txt这个文件
if err != nil {
//说明文件不存在,出现报错
fmt.Println(“打开文件失败:”, err.Error())
} else {
fmt.Println(“文件打开成功”)
fmt.Println(string(f))
}
}
go语言中通过自定义err来实现异常处理

//自定义err的两种方式
package main

import (
“errors”
“fmt”
)

func main() {
//自定义err的两种方式
err1 := errors.New(“这是一个自定义错误”)
//fmt.Println(err1.Error())
fmt.Println(err1) //要不要Error()都可以
err2 := fmt.Errorf(“这是一个自定义错误:%s,它是使用fmt生成的”, “fmt定义的错误”)
//fmt.Println(err2.Error())
fmt.Println(err2)
}
//案例:除法
package main

import (
“errors”
“fmt”
)

// 定义一个函数,来实现除法
func division(num1, num2 float64) (res float64, err error) {
fmt.Println(“需要计算的数字是:”, num1, num2)
if num2 == 0 {
return 0, errors.New(“输入的分母不能为0”)
} else {
res = num1 / num2
return res, nil
}
}

func main() {
res, err := division(2, 0)
if err != nil {
fmt.Println(“计算错误”, err.Error())
} else {
fmt.Println(“计算结果”, res)
}
}
但是以上定义的err,如果出现了错误,程序也不会停止,会一直运行

那么如何在出现错误时终止程序呢

package main

import (
“errors”
“fmt”
“time”
)

func connectDatabase(address string, port int) (string, error) {
//如果address和port为空
if address == “” || port == 0 {
return “”, errors.New(“无法链接数据库”)
} else {
return “数据库链接成功”, nil
}
}

func main() {
// panic:可以在异常的时候让程序终止执行,退出程序。或者是程序所强依赖的基础组件不可用
// 此时程序已经无法继续正常工作,此时可以使用panic抛出异常,并且把程序退出
s, err := connectDatabase(“”, 0)
for {
time.Sleep(time.Second * 5)
if err != nil {
//说明无法链接数据库
fmt.Println(err)
panic(err) //此时就会退出程序
} else {
//说明链接成功
fmt.Println(s)
}
}
}
那么终止程序后,我们需不需要做一些处理呢,比如终止程序后,我们需要发一些消息给前端

这时就可以使用到defer:是go语言中的一种延迟调用机制,defer里面的内容可以在函数return之前或者是程序panic之前执行

defer是可以有多个的,采用先进后出的机制;一般用于资源回收和数据返回,defer也可以用于异常时的恢复

defer后跟函数调用

package main

import (
“errors”
“fmt”
)

// 实现数据库的链接
func connectDatabase(address string, port int) (string, error) {
// 如果address和port为空
if address == “” || port == 0 {
return “”, errors.New(“无法链接数据库”)
} else {
return “数据库链接成功”, nil
}
}

// 返回数据给前端
func returnDataToFrontend(msg string) {
fmt.Println(“返回给前端的数据是:”, msg)
}

func main() {
msg := “返回给前端的数据”

defer returnDataToFrontend(msg) // defer不会真正的执行

_, err := connectDatabase("", 0)
if err != nil {
	fmt.Println(err)
	// defer会在这一步执行
	panic(err)
}

}
以上是终止程序后,将终止信息返回给管理员,那么我们又该如果将捕获到的错误信息进行相应的处理,从而让程序继续执行,不中断

package main

import “fmt”

func printSliceData(s []string) {
//使用recover进行异常捕获
defer func() {
fmt.Println(“程序执行失败,捕获异常”)
if err := recover(); err != nil {
// recover是用来捕获panic的报错的,尝试恢复,防止程序异常退出
fmt.Println(“捕获一个错误:”, err)
}
}()

fmt.Println("切片的内容:", s)
fmt.Println("切片的第三个值:", s[2]) //这里由于下标超出,程序会自己生成一个panic,从而终止程序

}

func main() {
s := []string{“a”, “b”}
printSliceData(s)
}
Go自定义类型
结构体
go语言中的结构体是一种自定义数据类型,可以将不同类型的数据组合在一起形成一个单独的实体

package main

import “fmt”

/*
type 结构体名 struct {
属性1 类型
属性2 类型
}

var 变量名 结构体名{
属性1: 值1
属性2: 值2
}
*/

func main() {
//定义一个名为People的结构体
type People struct {
name string
age int
address string
}
//先定义再赋值
var p1 People
p1.name = “华子”
p1.age = 18
p1.address = “陕西省汉中市”
fmt.Println(p1) //{华子 18 陕西省汉中市}
//直接声明
p2 := People{
name: “huazi”,
age: 19,
address: “陕西省汉中市”,
}
fmt.Println(p2) //{huazi 19 陕西省汉中市}
//第三种方式
var p3 People = People{“hua”, 20, “陕西省汉中市”}
fmt.Println(p3) //{hua 20 陕西省汉中市}

//使用
fmt.Printf("名字:%s  年龄:%d\n", p2.name, p2.age)
//修改值
p2.name = "华"
fmt.Printf("名字:%s  年龄:%d\n", p2.name, p2.age)
//赋值
p4 := p2
fmt.Println(p4)
//判断自定义变量是否相等
fmt.Println(p4 == p2)

}
属性是这样定义的,那么方法该如何定义呢

package main

import “fmt”

//定义一个名为People的结构体
type People struct {
name string
age int
address string
}

//定义结构体的方式函数
func (p *People) getInfo() string {
return fmt.Sprintf(“当前用户名:%s 年龄:%d 地址:%s\n”,
p.name, p.age, p.address)
}

func (p *People) Eat(food string) {
fmt.Printf(“%s今天吃了%s\n”, p.name, food)
}

func main() {
var p1 People = People{“华子”, 18, “陕西省汉中市”}
//调用方法:
//变量.方法名()
fmt.Println(p1.getInfo())
p1.Eat(“鸡公煲”)
}
go变量大小写特性
getInfo小写开头的变量名,是私有元素,只能在本包内使用

Eat大写开头的变量名,是公开元素,可以被外部的包调用

指针类型和值类型的方法
指针类型的方法
package main

import “fmt”

//定义一个名为People的结构体
type People struct {
name string
age int
address string
}

/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*/

//定义结构体的方式函数(指针类型)
func (p *People) getInfo() string {
p.age = 99
return fmt.Sprintf(“当前用户名:%s 年龄:%d 地址:%s\n”,
p.name, p.age, p.address)
}

func main() {
var p1 People = People{“华子”, 18, “陕西省汉中市”}
//调用方法:
//变量.方法名()
fmt.Println(p1.getInfo()) //当前用户名:华子 年龄:99 地址:陕西省汉中市
fmt.Println(p1) //{华子 99 陕西省汉中市}
}
值类型的方法
package main

import “fmt”

//定义一个名为People的结构体
type People struct {
name string
age int
address string
}

/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*/

//定义结构体的方式函数(值类型)
func (p People) getInfo() string {
p.age = 99
return fmt.Sprintf(“当前用户名:%s 年龄:%d 地址:%s\n”,
p.name, p.age, p.address)
}

func main() {
var p1 People = People{“华子”, 18, “陕西省汉中市”}
//调用方法:
//变量.方法名()
fmt.Println(p1.getInfo()) //当前用户名:华子 年龄:99 地址:陕西省汉中市
fmt.Println(p1) //{华子 18 陕西省汉中市}
}
嵌套
第一种嵌套方式
package main

import “fmt”

type Phone struct {
mode string
price int
}

type People struct {
name string
age int
address string
mobile Phone //People结构体中嵌套Phone
}

func (p *People) getInfo() string {
return fmt.Sprintf(“姓名:%s 手机:%s”, p.name, p.mobile.mode)
}

func main() {
var p1 People
p1.name = “华子”
p1.age = 18
p1.address = “陕西省汉中市”
p1.mobile.mode = “小米17”
p1.mobile.price = 1999
fmt.Println(p1.getInfo())
}
第二种嵌套方式
package main

import “fmt”

type Phone struct {
mode string
price int
}

type People struct {
name string
age int
address string
}

type info struct { //再写一个info结构体,将People和Phone合起来
Phone
People
}

func (p *info) getInfo() string {
return fmt.Sprintf(“姓名:%s 手机:%s”, p.name, p.mode)
}

func main() {
var p1 info
p1.name = “华子”
p1.age = 20
p1.address = “陕西省汉中市”
p1.mode = “小米”
p1.price = 1999
fmt.Println(p1.getInfo())
}
如果多个结构体上有相同的变量名,就不能直接进行赋值了

//如果多个结构体上有相同的变量名,就不能直接进行赋值了
package main

import “fmt”

type Phone struct {
name string
price int
}

type People struct {
name string
age int
address string
}

type info struct { //再写一个info结构体,将People和Phone合起来
Phone
People
}

func (p *info) getInfo() string {
return fmt.Sprintf(“姓名:%s 手机:%s”, p.People.name, p.Phone.name)
}

func main() {
var p1 info
p1.People.name = “华子”
p1.age = 20
p1.address = “陕西省汉中市”
p1.Phone.name = “小米”
p1.price = 1999
fmt.Println(p1.getInfo())
}
interface接口类型
go语言的接口是一种类型,定义了一组方法的集合,但是接口又不需要去实现他们,这些方法可以被不同的类型实现,进而就是这个类型实现了这个接口。

在go语言中,接口是一个重要的概念,接口被广泛应用于许多标准库和框架中。通过接口,可以使不同的类型之间实现相同的行为,从而达到代码复用和扩展的目的,并且可以实现不同类型之间的无缝切换。

在这里插入图片描述

不用接口之前
//对每个数据库的操作都要写不同的操作语句
package main

import “fmt”

//创建一个数据库的结构体,用来存放数据库的连接信息
type DBConfig struct {
User string
Password string
Host string
Port int
Database string
}

func main() {
//声明一个mysql数据库实例
db := DBConfig{“root”, “password”, “127.0.0.1”, 3306, “interface_test”}
fmt.Println(“mysql数据库的配置:”, db)
//插入一条数据
fmt.Println(“在mysql中插入一条数据:db.row(‘insert xxx to user’).Rows()”)

//换成pg
//生成pg数据库的连接实例
dbPg := DBConfig{"root", "password", "127.0.0.1", 3306, "interface_test"}
fmt.Println("pg数据库的配置:", dbPg)
//在pg中插入一条数据
fmt.Println("在pg中插入一条数据:db.QueryRow('insert xxx to user')")

}
使用接口之后
package main

import “fmt”

/*
type 接口名 interface {
方法名(参数) 返回值
方法名(参数) 返回值
方法名(参数) 返回值
}
*/

type DBCommon interface {
Insert(string) error
Update(string) error
Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
User string
Password string
Host string
Port int
Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
config DBConfig
charSet string
}

func (m MySQL) Insert(data string) error {
fmt.Println(“插入数据到MySQL:”, data)
return nil
}

func (m MySQL) Update(data string) error {
fmt.Println(“更新数据到MySQL:”, data)
return nil
}

func (m MySQL) Delete(data string) error {
fmt.Println(“删除数据到MySQL:”, data)
return nil
}

func main() {
db := DBConfig{“root”, “password”, “127.0.0.1”, 3306, “interface_test”}
//声明一个接口的变量
var dbCommonInterface DBCommon
var m MySQL
m.config = db
m.charSet = “utf-8”
dbCommonInterface = m //将结构体变量赋值给接口变量
dbCommonInterface.Insert(“insert”) //调用接口中的定义的函数
dbCommonInterface.Update(“update”)
dbCommonInterface.Delete(“delete”)
}
package main

import “fmt”

/*
type 接口名 interface {
方法名(参数) 返回值
方法名(参数) 返回值
方法名(参数) 返回值
}
*/

type DBCommon interface {
Insert(string) error
Update(string) error
Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
User string
Password string
Host string
Port int
Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
config DBConfig
charSet string
}

func (m MySQL) Insert(data string) error {
fmt.Println(“插入数据到MySQL:”, data)
return nil
}

func (m MySQL) Update(data string) error {
fmt.Println(“更新数据到MySQL:”, data)
return nil
}

func (m MySQL) Delete(data string) error {
fmt.Println(“删除数据到MySQL:”, data)
return nil
}

type PostgreSQL struct {
config DBConfig
charSet string
}

func (m PostgreSQL) Insert(data string) error {
fmt.Println(“插入数据到PostgreSQL:”, data)
return nil
}

func (m PostgreSQL) Update(data string) error {
fmt.Println(“更新数据到PostgreSQL:”, data)
return nil
}

func (m PostgreSQL) Delete(data string) error {
fmt.Println(“删除数据到PostgreSQL:”, data)
return nil
}

func main() {
db := DBConfig{“root”, “password”, “127.0.0.1”, 3306, “interface_test”}
//声明一个接口的变量
var dbCommonInterface DBCommon
//var m MySQL
var m PostgreSQL
m.config = db
m.charSet = “utf-8”
dbCommonInterface = m
dbCommonInterface.Insert(“insert”)
dbCommonInterface.Update(“update”)
dbCommonInterface.Delete(“delete”)
}
package main

import “fmt”

/*
type 接口名 interface {
方法名(参数) 返回值
方法名(参数) 返回值
方法名(参数) 返回值
}
*/

type DBCommon interface {
Insert(string) error
Update(string) error
Delete(string) error
}

//定义结构体存储数据库的信息
type DBConfig struct {
User string
Password string
Host string
Port int
Database string
}

//定义一个类型去实现这个接口
type MySQL struct {
config DBConfig
charSet string
}

func (m MySQL) Insert(data string) error {
fmt.Println(“插入数据到MySQL:”, data)
return nil
}

func (m MySQL) Update(data string) error {
fmt.Println(“更新数据到MySQL:”, data)
return nil
}

func (m MySQL) Delete(data string) error {
fmt.Println(“删除数据到MySQL:”, data)
return nil
}

type PostgreSQL struct {
config DBConfig
charSet string
}

func (m PostgreSQL) Insert(data string) error {
fmt.Println(“插入数据到PostgreSQL:”, data)
return nil
}

func (m PostgreSQL) Update(data string) error {
fmt.Println(“更新数据到PostgreSQL:”, data)
return nil
}

func (m PostgreSQL) Delete(data string) error {
fmt.Println(“删除数据到PostgreSQL:”, data)
return nil
}

type sqlServer struct {
config DBConfig
charSet string
}

func (m sqlServer) Insert(data string) error {
fmt.Println(“插入数据到sqlServer:”, data)
return nil
}

func (m sqlServer) Update(data string) error {
fmt.Println(“更新数据到sqlServer:”, data)
return nil
}

func (m sqlServer) Delete(data string) error {
fmt.Println(“删除数据到sqlServer:”, data)
return nil
}

func main() {
dbType := “sqlserver”

//声明一个接口的变量
var dbCommonInterface DBCommon
if dbType == "mysql" {
	var m MySQL
	dbCommonInterface = m
} else if dbType == "PostgreSQL" {
	var pg PostgreSQL
	dbCommonInterface = pg
} else {
	var sqlS sqlServer
	dbCommonInterface = sqlS
}
dbCommonInterface.Insert("insert")
dbCommonInterface.Update("update")
dbCommonInterface.Delete("delete")

}
空接口
方法1
package main

import “fmt”

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

//定义一个空接口
type EmptyInterface interface{}

func main() {
var ei EmptyInterface //ei是一个空接口类型的变量,可以接受任何类型的赋值
s1 := “这是一个字符串”
i1 := 72578
ei = s1
fmt.Println(ei)
ei = i1
fmt.Println(ei)
}
方法2
package main

import “fmt”

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

func main() {
s1 := “这是一个字符串”
i1 := 18
//定义空接口方法2
var ei1 interface{}
ei1 = s1
fmt.Println(ei1)
ei1 = i1
fmt.Println(ei1)
}
package main

import “fmt”

/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/

func main() {
//map记录联系方式:手机号(int) 座机号(010-123-789)string类型
contacts := make(map[string]interface{}) //在map中定义空接口可以接受不同类型的值
contacts[“huazi”] = 13289446832
contacts[“dot”] = “010-123-789”
fmt.Println(contacts)
}
在这里插入图片描述

接口类型断言和类型判断
package main

import “fmt”

/*
类型断言:大致知道了接口可能是某种类型,然后使用t,ok := 变量.(类型)
类型判断:switch t := 变量.(type){}
*/

func dealData(data interface{}) {
t, ok := data.(string) //如果data是string类型,则返回true给ok,t接受data的值,否则t接受空值
if ok {
fmt.Println(“当前类型为string,变量的值是:”, t)
} else {
fmt.Println(“data不是字符串”)
fmt.Println(“当前t的值:”, t)
}
}

func main() {
s := “这是一个字符串”
dealData(s)
i := 123456
dealData(i)
}
package main

import “fmt”

func getType(i interface{}) {
switch t := i.(type) {
case int:
fmt.Println(“当前值为int类型:”, t)
case string:
fmt.Println(“当前值为string类型:”, t)
case bool:
fmt.Println(“当前值为bool类型:”, t)
default:
fmt.Println(“当前类型不在处理范围”)
}
}

func main() {
s := “这个一个字符串”
getType(s)
i := 123
getType(i)
var emtry interface{}
getType(emtry)

}
接口嵌套和继承
package main

import “fmt”

type Generic_i interface {
Login()
LogOut()
}

type VIP_i interface {
Consult()
}

type User_i interface {
Generic_i
}

type VIPUser_i interface {
Generic_i
VIP_i
}

type Userordinary_s struct {
Name string
}

func (u Userordinary_s) Login() {
fmt.Println(“用户已登录:”, u.Name)
}
func (u Userordinary_s) LogOut() {
fmt.Println(“用户已退出:”, u.Name)
}

type Uservip_s struct {
Name string
}

func (u Uservip_s) Login() {
fmt.Println(“vip用户已登录:”, u.Name)
}
func (u Uservip_s) LogOut() {
fmt.Println(“vip用户已退出:”, u.Name)
}
func (u Uservip_s) Consult() {
fmt.Println(“vip用户可以进行咨询:”, u.Name)
}

func main() {
var userinterface User_i
u := Userordinary_s{
Name: “华子”,
}
userinterface = u
userinterface.Login()
userinterface.LogOut()

var vipuserinterface VIPUser_i
vipu := Uservip_s{
	Name: ".",
}
vipuserinterface = vipu
vipuserinterface.Login()
vipuserinterface.LogOut()
vipuserinterface.Consult()

}


网站公告

今日签到

点亮在社区的每一天
去签到