Go语言从入门到精通
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 mainimport "fmt"func main() {//方式1:fmt.Scanln(指针)var name stringvar age bytevar salary float32var 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 mainimport "fmt"func main() {//方式2:fmt.Scanf()var name stringvar age bytevar salary float32var isPass boolfmt.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 mainimport "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 = 18name3 string = "huazi")fmt.Println(name3, age1)//当省略类型后,go会自动判断,自动转换为强数据类型var (name4 = "huazi"age2 = 18)fmt.Println(name4, age2)//当省略了var,只能再函数内使用,要用:= ,称之为语法糖//相当于var变成了:name5 := "huazi" //我们成为语法糖写法age3 := 18fmt.Println(name5, age3)//交换变量的值name6 := "hua"name7 := "huazi"name6, name7 = name7, name6 fmt.Println(name6, name7)//reflect.TypeOf(变量名) 打印变量的类型或者使用%T来表示类型fmt.Println(reflect.TypeOf(name6))
}
在函数外定义并赋值的变量是包级别的变量,这种变量可以不对其进行使用。但是在函数中定义的变量必须得到使用
函数外不能使用语法糖来定义变量
常量
package mainimport ("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)//常量可以省略类型,但是不能省略constconst (name4 = "ze"age1 = 18)fmt.Println(name4, age1)age1 = 20 //会报错,因为常量不能修改const (num1 int = 1num2num3str1 string = "hua"str2str3)fmt.Println(num1, num2, num3) //1 1 1fmt.Println(str1, str2, str3) //hua hua hua//枚举(const+iota),iota的基数是0const (e1 int = (1 + iota) * 10e2e3)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 stringAge 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 mainimport ("fmt"
)func main() {num1 := 1{num2 := 2fmt.Println(num1)fmt.Println(num2)}//fmt.Println(num2) //报错
}
package mainimport ("fmt"
)func printAll() {fmt.Println("今天是个好日子")fmt.Println("hello world")num1 := 1fmt.Println(num1)
}
func main() {printAll() //调用函数//fmt.Println(num1) 报错
}
运算符
- 算术运算
package mainimport "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 := 1num2 := 2Calculate(num1, num2) //值传递
}
- 字符串拼接
package mainimport "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 := 8p1++fmt.Println("p1 =", p1)p1--fmt.Println("p1 =", p1)
package mainimport "fmt"func main() {a := 3b := 2fmt.Println(a / b) //取整 1fmt.Println(float64(a) / float64(b)) // 1.5小数运算
}
浮点数不能和整数一起运算
float32类型的和float64类型的不能运算
int类型和float类型
package mainimport ("fmt""math""reflect"
)func main() {// 数值类型:int int8 int16 int32 int64 uint// int: 正负数 uint:不带符号的数字 // intdefaultIntType := 1fmt.Println("默认的数值类型是:", reflect.TypeOf(defaultIntType))// int和操作系统是有关系的// 64位的,int64 32位的 int32var int64Num int64 = 1fmt.Println("int64Num的数值类型是:", reflect.TypeOf(int64Num))var uintNum uint = 1fmt.Println("uintNum的数值类型是:", reflect.TypeOf(uintNum))fmt.Println("int的取值范围:", math.MinInt, math.MaxInt)fmt.Println("uint的取值范围:", uint(math.MaxUint))fmt.Println(18446744073709551615 > 9223372036854775807)// float float32和float64var floatNum1 float64 = 3.14var floatNum2 float32 = 3.15// floatSum := floatNum1 + floatNum2fmt.Println(floatNum1, floatNum2)
}
关系与逻辑运算符
package mainimport ("fmt""reflect"
)func main() {// 大于, 小于fmt.Println(727585 > 727588) // falsefmt.Println(727585 < 727588) // true// 是否相等, =和==的区别fmt.Println("a" == "b") // falsefmt.Println(3.14 == 3.14)s1 := "dukuan"s2 := "dotbalo"// xxx := s1 == s2fmt.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 := 1n2 := 1n3 := 2// 与: 所有的表达式都为true,最终的结果就为truefmt.Println(n1 == n2 && n2 == n3) // true false => false// 或:任意一个为true,最终结果就为truefmt.Println(n1 == n2 || reflect.TypeOf(n3).Kind() == reflect.String)
}
if-else
package mainimport ("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 mainimport "fmt"func backBool() bool {return true
}func main() {a := falseif res := backBool(); res != a { //在判断前,先进行运算fmt.Println("true")} else {fmt.Println("false")}
}
switch
package mainimport ("fmt"
)func printScore(score int) {sc := score / 10switch sc {case 10, 9:fmt.Println("优秀")breakcase 8:fmt.Println("良好")case 7:fmt.Println("中等")case 6:fmt.Println("及格")default:fmt.Println("不及格")}
}func main() {printScore(66)
}
break默认可以省略不写
for
package mainimport ("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 mainimport ("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 mainimport ("fmt"
)func main() {temp := 20count := 0for {if count == 20 {fmt.Println("恭喜你找到了", temp)break} else {count++}}
}
package mainimport ("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 mainimport "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 mainimport "fmt"func main() {// 切片:切片的长度是不固定的,可以扩容// var 切片名称 = []切片类型{value1, value2...}var slice1 []int //先定义切片fmt.Println(slice1) // []// 切片默认的两个属性:1.切片的长度,表示切片中有多少个元素 2.切片的容量,表示切片中最大可以放多少个元素fmt.Println("切片的默认长度是:", len(slice1)) // 0fmt.Println("切片的默认容量:", cap(slice1)) // 0// 添加元素slice1 = append(slice1, 1, 2, 3, 4)fmt.Println(slice1) // [1 2 3 4]fmt.Println("长度:", len(slice1)) // 4fmt.Println("容量:", cap(slice1)) // 4// 修改数据slice1[0] = 88fmt.Println(slice1) // [88 2 3 4]//定义切片并初始化var slice2 = []string{"切片1", "切片2", "切片3"}fmt.Println(slice2) // [0 0 0 0 0]fmt.Println("切片的长度:", len(slice2)) // 3fmt.Println("切片的容量:", cap(slice2)) // 3slice2 = 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)) // 5fmt.Println("切片的默认容量:", cap(slice3)) // 10slice3 = 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 mainimport "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 mainimport "fmt"func main() {str1 := "huazi"str2 := str1 //深拷贝fmt.Println(str1, str2) //huazi huazistr2 = "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] = 88fmt.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 mainimport ("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的修改不影响slice1fmt.Println(slice1, slice2)//打印内存地址fmt.Println("slice1的内存地址", unsafe.Pointer(&slice1)) //1fmt.Println("slice1[0]的内存地址", unsafe.Pointer(&slice1[0])) //2fmt.Println("slice2的内存地址", unsafe.Pointer(&slice2)) //3fmt.Println("slice2[0]的内存地址", unsafe.Pointer(&slice2[0])) //4
}
map映射
package mainimport "fmt"func main() {// var map名 = map[type]type{key1:value1, key2:value2......}teacherAge := make(map[string]int)fmt.Println("map的初始化值", teacherAge) //map[]teacherAge["huazi"] = 18teacherAge["xiaoming"] = 20teacherAge["huazi"] = 22fmt.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 rangefor k, v := range teacherAddress {fmt.Printf("%s老师的地址:%s\n", k, v)}fmt.Println("取一个不存在的值:", teacherAddress["hhhh"]) //空字符串//map中的ok判断value, ok := teacherAddress["hua"] //如果hua这个键不存在返回false,存在返回trueif 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 mainimport "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 mainimport ("fmt"
)func main() {//map对象嵌套map对象// map[string]map[string]stringaddress1 := map[string]string{"汉中市": "洋县","宝鸡市": "凤县",}address2 := map[string]string{"武功市": "好县","花市": "中等县",}var country map[string]map[string]stringcountry = make(map[string]map[string]string)country["陕西省"] = address1country["浙江省"] = address2fmt.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 mainimport ("fmt""math"
)// 参数类型为float64,返回值类型为float64
func area(r float64) float64 {s := math.Pi * r * rreturn s
}func main() {r := 5 //此时r默认为int类型s := area(float64(r)) //需要使用float64()把int转为float64fmt.Println("面积是:", s)
}
package mainimport ("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 mainimport ("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 mainimport ("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, "我"))// 此处的视频出现错误,应该是HasSuffixfmt.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 mainimport "fmt"func updateString(s string) {s = "这是一个新值"
}
func updateStringWithPointer(s *string) {*s = "这是一个新值"
}func main() {var s strings = "这是一个字符串"fmt.Println("变量s的内存地址是:", &s)// sp: 指针// 内存地址: 通过&符号进行取值sp := &sfmt.Println("指针sp:", sp)var sp2 *stringfmt.Println("指针sp2:", sp2) // 指针未进行赋值的时候为nilsp2 = &sfmt.Println("指针sp2:", sp2)// 通过指针获取内存地址的值fmt.Println("指针对应内存地址的值:", *sp2)updateString(s)fmt.Println("修改后的s:", s)updateStringWithPointer(&s)fmt.Println("真正修改后的s:", s)
}
函数
函数的定义
package mainimport "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 mainimport "fmt"func intSum(a, b int) (sum int) {sum = a + breturn
}func main() {fmt.Println(intSum(1, 3))
}
package mainimport "fmt"func sortInt(a, b int) (min, max int) {if a < b {min = amax = b} else {min = bmax = a}return
}func main() {min, max := sortInt(99, 88)fmt.Println(min, max)
}
不定长参数
package mainimport ("fmt""strings"
)// 接收不定长度参数的函数
func randomLength(s ...string) string {//接受到的多个参数会封装成一个切片fmt.Println(s) //[hua zi]m := strings.Join(s, "") //huazireturn m
}func main() {m := randomLength("hua", "zi")fmt.Println(m)
}
递归函数
package mainimport "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 mainimport "fmt"func main() {//定义匿名函数并调用func() {fmt.Println("这个匿名函数")}()
}
异常处理
go语言中有一种错误类型叫error
package mainimport ("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 mainimport ("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 mainimport ("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 / num2return res, nil}
}func main() {res, err := division(2, 0)if err != nil {fmt.Println("计算错误", err.Error())} else {fmt.Println("计算结果", res)}
}
但是以上定义的err,如果出现了错误,程序也不会停止,会一直运行
那么如何在出现错误时终止程序呢
package mainimport ("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 mainimport ("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 mainimport "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 mainimport "fmt"/*
type 结构体名 struct {属性1 类型属性2 类型
}var 变量名 结构体名{属性1: 值1属性2: 值2
}
*/func main() {//定义一个名为People的结构体type People struct {name stringage intaddress string}//先定义再赋值var p1 Peoplep1.name = "华子"p1.age = 18p1.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 := p2fmt.Println(p4)//判断自定义变量是否相等fmt.Println(p4 == p2)
}
属性是这样定义的,那么方法该如何定义呢
package mainimport "fmt"//定义一个名为People的结构体
type People struct {name stringage intaddress 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 mainimport "fmt"//定义一个名为People的结构体
type People struct {name stringage intaddress string
}/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*///定义结构体的方式函数(指针类型)
func (p *People) getInfo() string {p.age = 99return 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 mainimport "fmt"//定义一个名为People的结构体
type People struct {name stringage intaddress string
}/*
自定义类型添加方法使用值类型和指针类型的区别
p:接受者,方法的参数
People:接受者的类型:分为值类型和指针类型
*///定义结构体的方式函数(值类型)
func (p People) getInfo() string {p.age = 99return 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 mainimport "fmt"type Phone struct {mode stringprice int
}type People struct {name stringage intaddress stringmobile Phone //People结构体中嵌套Phone
}func (p *People) getInfo() string {return fmt.Sprintf("姓名:%s 手机:%s", p.name, p.mobile.mode)
}func main() {var p1 Peoplep1.name = "华子"p1.age = 18p1.address = "陕西省汉中市"p1.mobile.mode = "小米17"p1.mobile.price = 1999fmt.Println(p1.getInfo())
}
- 第二种嵌套方式
package mainimport "fmt"type Phone struct {mode stringprice int
}type People struct {name stringage intaddress string
}type info struct { //再写一个info结构体,将People和Phone合起来PhonePeople
}func (p *info) getInfo() string {return fmt.Sprintf("姓名:%s 手机:%s", p.name, p.mode)
}func main() {var p1 infop1.name = "华子"p1.age = 20p1.address = "陕西省汉中市"p1.mode = "小米"p1.price = 1999fmt.Println(p1.getInfo())
}
如果多个结构体上有相同的变量名,就不能直接进行赋值了
//如果多个结构体上有相同的变量名,就不能直接进行赋值了
package mainimport "fmt"type Phone struct {name stringprice int
}type People struct {name stringage intaddress string
}type info struct { //再写一个info结构体,将People和Phone合起来PhonePeople
}func (p *info) getInfo() string {return fmt.Sprintf("姓名:%s 手机:%s", p.People.name, p.Phone.name)
}func main() {var p1 infop1.People.name = "华子"p1.age = 20p1.address = "陕西省汉中市"p1.Phone.name = "小米"p1.price = 1999fmt.Println(p1.getInfo())
}
interface接口类型
go语言的接口是一种类型,定义了一组方法的集合,但是接口又不需要去实现他们,这些方法可以被不同的类型实现,进而就是这个类型实现了这个接口。
在go语言中,接口是一个重要的概念,接口被广泛应用于许多标准库和框架中。通过接口,可以使不同的类型之间实现相同的行为,从而达到代码复用和扩展的目的,并且可以实现不同类型之间的无缝切换。
- 不用接口之前
//对每个数据库的操作都要写不同的操作语句
package mainimport "fmt"//创建一个数据库的结构体,用来存放数据库的连接信息
type DBConfig struct {User stringPassword stringHost stringPort intDatabase 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 mainimport "fmt"/*
type 接口名 interface {方法名(参数) 返回值方法名(参数) 返回值方法名(参数) 返回值
}
*/type DBCommon interface {Insert(string) errorUpdate(string) errorDelete(string) error
}//定义结构体存储数据库的信息
type DBConfig struct {User stringPassword stringHost stringPort intDatabase string
}//定义一个类型去实现这个接口
type MySQL struct {config DBConfigcharSet 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 DBCommonvar m MySQLm.config = dbm.charSet = "utf-8"dbCommonInterface = m //将结构体变量赋值给接口变量dbCommonInterface.Insert("insert") //调用接口中的定义的函数dbCommonInterface.Update("update")dbCommonInterface.Delete("delete")
}
package mainimport "fmt"/*
type 接口名 interface {方法名(参数) 返回值方法名(参数) 返回值方法名(参数) 返回值
}
*/type DBCommon interface {Insert(string) errorUpdate(string) errorDelete(string) error
}//定义结构体存储数据库的信息
type DBConfig struct {User stringPassword stringHost stringPort intDatabase string
}//定义一个类型去实现这个接口
type MySQL struct {config DBConfigcharSet 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 DBConfigcharSet 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 MySQLvar m PostgreSQLm.config = dbm.charSet = "utf-8"dbCommonInterface = mdbCommonInterface.Insert("insert")dbCommonInterface.Update("update")dbCommonInterface.Delete("delete")
}
package mainimport "fmt"/*
type 接口名 interface {方法名(参数) 返回值方法名(参数) 返回值方法名(参数) 返回值
}
*/type DBCommon interface {Insert(string) errorUpdate(string) errorDelete(string) error
}//定义结构体存储数据库的信息
type DBConfig struct {User stringPassword stringHost stringPort intDatabase string
}//定义一个类型去实现这个接口
type MySQL struct {config DBConfigcharSet 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 DBConfigcharSet 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 DBConfigcharSet 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 DBCommonif dbType == "mysql" {var m MySQLdbCommonInterface = m} else if dbType == "PostgreSQL" {var pg PostgreSQLdbCommonInterface = pg} else {var sqlS sqlServerdbCommonInterface = sqlS}dbCommonInterface.Insert("insert")dbCommonInterface.Update("update")dbCommonInterface.Delete("delete")
}
空接口
- 方法1
package mainimport "fmt"/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*///定义一个空接口
type EmptyInterface interface{}func main() {var ei EmptyInterface //ei是一个空接口类型的变量,可以接受任何类型的赋值s1 := "这是一个字符串"i1 := 72578ei = s1fmt.Println(ei)ei = i1fmt.Println(ei)
}
- 方法2
package mainimport "fmt"/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/func main() {s1 := "这是一个字符串"i1 := 18//定义空接口方法2var ei1 interface{}ei1 = s1fmt.Println(ei1)ei1 = i1fmt.Println(ei1)
}
package mainimport "fmt"/*
空接口:空接口不会定义任何的方法
空接口是可以接受任何类型的参数值
*/func main() {//map记录联系方式:手机号(int) 座机号(010-123-789)string类型contacts := make(map[string]interface{}) //在map中定义空接口可以接受不同类型的值contacts["huazi"] = 13289446832contacts["dot"] = "010-123-789"fmt.Println(contacts)
}
接口类型断言和类型判断
package mainimport "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 := 123456dealData(i)
}
package mainimport "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 := 123getType(i)var emtry interface{}getType(emtry)}
接口嵌套和继承
package mainimport "fmt"type Generic_i interface {Login()LogOut()
}type VIP_i interface {Consult()
}type User_i interface {Generic_i
}type VIPUser_i interface {Generic_iVIP_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_iu := Userordinary_s{Name: "华子",}userinterface = uuserinterface.Login()userinterface.LogOut()var vipuserinterface VIPUser_ivipu := Uservip_s{Name: "戈兄",}vipuserinterface = vipuvipuserinterface.Login()vipuserinterface.LogOut()vipuserinterface.Consult()
}
相关文章:
Go语言从入门到精通
go相关命令 //对go源码进行编译,生成.exe文件 go build go文件名//直接运行go源码(生成.exe文件执行后,又删除.exe文件) go run go文件名go中的package和import /*package:用来声明这个文件是属于哪个包的*/ package…...
捉虫记录02-Nacos访问失败
目录 一、问题 二、排查 三、解决方案 一、问题 在访问nacos的时候出现以下问题: 二、排查 先用docker logs nacos来查找报错信息 docker logs nacos 看问题报错就是数据源问题,nacos没能连接上mysql 三、解决方案 第一步 docker restart mysql …...
安宝特方案 | AR助力紧急救援,科技守卫生命每一刻!
在生死时速的紧急救援战场上,每一秒都至关重要!随着科技的发展,增强现实(AR)技术正在逐步渗透到医疗健康领域,改变着传统的医疗服务模式。 安宝特AR远程协助解决方案,凭借其先进的技术支持和创新…...
超详细:Redis分布式锁
如何基于 Redis 实现一个最简易的分布式锁? 不论是本地锁还是分布式锁,核心都在于“互斥”。 在 Redis 中, SETNX 命令是可以帮助我们实现互斥。SETNX 即 SET if Not eXists (对应 Java 中的 setIfAbsent 方法),如果 key 不存在…...
@Autowired 和 @Resource思考(注入redisTemplate时发现一些奇怪的现象)
1. 前置知识 Configuration public class RedisConfig {Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template new RedisTemplate<>();template.setConnectionFactory(facto…...
MTK主板定制_联发科主板_MTK8766/MTK8768/MTK8788安卓主板方案
主流市场上的MTK主板通常采用联发科的多种芯片平台,如MT8766、MT6765、MT6762、MT8768和MT8788等。这些芯片基于64位Cortex-A73/A53架构,提供四核或八核配置,主频可达2.1GHz,赋予设备卓越的计算与处理能力。芯片采用12纳米制程工艺…...
k8s篇之控制器类型以及各自的适用场景
1. k8s中控制器介绍 在 Kubernetes 中,控制器(Controller)是集群中用于管理资源的关键组件。 它们的核心作用是确保集群中的资源状态符合用户的期望,并在需要时自动进行调整。 Kubernetes 提供了多种不同类型的控制器,每种控制器都有其独特的功能和应用场景。 2. 常见的…...
VideoCrafter模型部署教程
一、介绍 VideoCrafter是一个功能强大的AI视频编辑和生成工具,它结合了深度学习和机器学习技术,为用户提供了便捷的视频制作和编辑体验。 系统:Ubuntu22.04系统,显卡:4090,显存:24G 二、基础…...
mysql 与 mybatis 错误记录
DATE_FORMAT(FROM_UNIXTIME(start_time / 1000)只能传秒级时间戳,毫秒级时间戳group后不能select; tinyint(1)会被mybatis自动翻译为Boolean值,可以使用resultMap重新映射一下来解决,select使用了别名,在resultMap中映射column也必…...
本地git多用户ssh配置
仅作备份,不做解释 1. ~/.ssh/config Host jeadyx.gitee.com HostName gitee.com PreferredAuthentications publickey IdentityFile ~/.ssh/id_rsa_jeadyxHost jeady5.gitee.com HostName gitee.com PreferredAuthentications publickey IdentityFile ~/.ssh/id_…...
macbook外接2k/1080p显示器调试经验
准备工具 电脑 满足电脑和显示器要求的hdmi线或者转接头或者扩展坞 betterdisplay软件 Dell P2419H的最佳显示信息如下 飞利浦 245Es 2K的最佳显示比例如下 首选1152...
如何删除Kafka中的数据以及删除topic
如何删除Kafka数据已经以及删除topic呢? 1、删除数据 先启动Kafka实例 docker exec -it kafka-0 /bin/bash #进去容器 rm -rf /bitnami/kafka/data/* #删除数据 exit #退出如果删除失败,可能是数据不存在于/bitnami/kafka/data,使用 cd /o…...
wordpress二开-WordPress新增页面模板-说说微语
微语说说相当于一个简单的记事本,使用还是比较方便的。这个版本的说说微语CSS样式不兼容,可能有些主题无法适配,但是后台添加内容,前端显示的逻辑已经实现。可以当作Word press二开中自定义页面模板学习~ 一、后台添加说说微语模…...
Java学习笔记--数组常见算法:数组翻转,冒泡排序,二分查找
目录 一,数组翻转 二,冒泡排序 三,二分查找(一尺之锤,日取其半,万世不竭) 一,数组翻转 1.概述:数组对称索引位置上的元素互换,最大值数组序号是数组长度减一 创建跳板…...
使用 OpenAI 进行数据探索性分析(EDA)
探索性数据分析(Exploratory Data Analysis, 简称 EDA)是数据分析中不可或缺的环节,帮助分析师快速了解数据的分布、特征和潜在模式。传统的 EDA 通常需要手动编写代码或使用工具完成。现在,通过 OpenAI 的 GPT-4 模型,…...
Jdk1.8新特性
新增的类以及常用的方法 在Java的java.util.concurrent包中,除了之前提到的并发工具类外,还有一些新增的类以及它们常用的方法。以下是一些例子: 新增的类 CompletableFuture: CompletableFuture是Java 8中引入的一个类&a…...
丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU
目录 前言—— DAMODEL(丹摩智算) 算力服务 直观的感受算力提供商的强大 平台功能介绍 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…...
mock.js:定义、应用场景、安装、配置、使用
前言:什么是mock.js? 作为一个前端程序员,没有mockjs你不感觉很被动吗?你不感觉你的命脉被后端那个男人掌握了吗?所以,我命由我不由天!学学mock.js吧! mock.js 是一个用于生成随机…...
优化 MFC CGridCtrl 的表格布局与功能
在使用 MFC 的 CGridCtrl 控件创建表格时,遇到的一个典型问题是,当表格滚动条出现时,最后一列会显示空白。这篇博客将记录解决这一问题的详细过程,同时总结了 CGridCtrl 初始化及优化的关键步骤,帮助开发者快速搭建一个…...
Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失
Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失 Addressable Play Mode Script加载模式 选择 Use Existiing Build 1.Unity 切换到 PC 平台,执行 Addressable Build 运行,加载 bundle 内的预制体 显示正常 2.Unit…...
直播预告| 深入探索 DB-GPT GraphRAG 的设计解读与优化
前言 感谢DB-GPT的社区朋友持续关注我们的源码解读系列~在前几期的直播中,我们深入探讨了DB-GPT的架构设计、智能体工作流、Agent开发等话题,受到了热烈反响。 本期,我们邀请到了社区的老朋友,也是DB-GPT GraphRag的维…...
C语言:指针变量作为函数参数
在c语言中,函数的参数不仅可以是整数,小数、字符等具体的数据,还可以是指向他们的指针,用指针变量做函数,参数可以将函数外部的地址传递给函数内部,使得在函数内部可以操作函数外部的数据,并且这…...
机器学习基础06
目录 1.梯度下降 1.1梯度下降概念 1.2梯度下降公式 1.3学习率 1.4实现梯度下降 1.5API 1.5.1随机梯度下降SGD 1.5.2小批量梯度下降MBGD 1.6梯度下降优化 2.欠拟合过拟合 2.1欠拟合 2.2过拟合 2.3正则化 2.3.1L1正则项(曼哈顿距离) 2.3.2…...
RecyclerView详解——(四)缓存复用机制
稍微看了下源码和部分文章,在此做个小小的总结 RecyclerView,意思为可回收的view,那么相对于listview,他的缓存复用肯定是一大优化。 具体而言,当一个列表项被移出屏幕后,RecyclerView并不会销毁其视图&a…...
向量数据库FAISS之五:原理(LSH、PQ、HNSW、IVF)
1.Locality Sensitive Hashing (LSH) 使用 Shingling MinHashing 进行查找 左侧是字典,右侧是 LSH。目的是把足够相似的索引放在同一个桶内。 LSH 有很多的版本,很灵活,这里先介绍第一个版本,也是原始版本 Shingling one-hot …...
速盾:CDN缓存的工作原理是什么?
CDN(内容分发网络)是一种将内容分发到全球不同地理位置的网络架构,以提供更快速、可靠的内容传输。其核心原理是利用缓存技术,将数据内容分布到离用户最近的边缘节点上。当用户请求内容时,CDN将根据用户的IP地址&#…...
使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变
作者:来自 Elastic Greg Crist Elasticsearch 推出了一项新功能:Elastic AI Assistant for Search。你可以将其视为 Elasticsearch 和 Kibana 开发人员的内置指南,旨在回答问题、引导你了解功能并让你的生活更轻松。在 Microsoft AI Services…...
SQL基础语法介绍-基于MySQL
文章目录 一、SQL分类二、SQL语法1.数据库字段类型1.1.数值类型1.2 字符类型1.3 日期类型 2.字段约束2.1约束介绍2.2 非空约束(not null)2.3 唯一约束(unique)2.4 主键约束(primary key)2.5 自增长主键2.6 …...
android 性能分析工具(03)Android Studio Profiler及常见性能图表解读
说明:主要解读Android Studio Profiler 和 常见性能图表。 Android Studio的Profiler工具是一套功能强大的性能分析工具集,它可以帮助开发者实时监控和分析应用的性能,包括CPU使用率、内存使用、网络活动和能耗等多个方面。以下是对Android …...
【STM32项目】基于STM32设计的震动马达超声波电机高频震动——高级定时器PWM互补输出带死区控制
高级定时器PWM互补输出带死区控制 前言:实现高级定时器互补输出带死区控制,实现震动/超声波电机/马达,高频震动。使用 STM32F103 芯片输出两路互补 PWM,并带有死区和刹车控制功能。 定时器 1 通道 1 及其互补通道输出 PWM,且带死区控。当定时器 1 的刹车输入引脚被拉…...
深入探索Golang的GMP调度机制:源码解析与实现原理
在Golang(又称Go语言)的并发编程模型中,GMP调度模型扮演着举足轻重的角色。GMP分别代表Goroutine(协程)、M(Machine,即内核线程)和P(Processor,即逻辑处理器&…...
Django如何配置多个环境的MySQL数据库
在 Django 项目中配置多个环境的 MySQL 数据库是一个常见的需求,特别是在开发、测试和生产环境中使用不同的数据库配置。你可以通过在 settings.py 文件中使用条件语句或环境变量来实现这一点。 1. 使用环境变量 使用环境变量是一种灵活且安全的方式来配置多个环境…...
数据结构(链栈——c语言实现)
链式栈(Linked Stack)是一种基于链表数据结构实现的栈。它利用链表节点的指针来存储元素,并通过指针的链接关系来维护栈的后进先出(LIFO, Last In First Out)特性。 链式栈的优点 动态大小: 链式栈…...
FPGA实现串口升级及MultiBoot(九)BPI FLASH相关实例演示
本文目录索引 区别一:启动流程的区别区别二:高位地址处理区别三:地址映射例程说明总结例程地址之前一直都是以SPI FLASH为例进行相关知识讲解,今天我们介绍另一款常用的配置FLASH-BPI FLASH。 今天的讲解以简洁为主,主打个能用一句话不说两句话。以和SPI区别为主,实例演…...
Android 网络通信(三)OkHttp实现登入
学习笔记 目录 一. 先写XML布局 二、创建 LoginResponse 类 :封装响应数据 目的和作用: 三、创建 MyOkHttp 类 :发送异步请求 代码分析 可能改进的地方 总结 四、LoginActivity 类中实现登录功能 详细分析与注释: 总结: 改进建议: 零、响应数据样例 通过 P…...
java基础概念37:正则表达式2-爬虫
一、定义 【回顾】正则表达式的作用 作用一:校验字符串是否满足规则作用二:在一段文本中查找满足要求的内容——爬虫 二、本地爬虫VS网络爬虫 2-1、本地爬虫 示例: 代码优化: public static void main(String[] args) {// 大…...
【大数据学习 | Spark-Core】RDD的概念与Spark任务的执行流程
1. RDD的设计背景 在实际应用中,存在许多迭代式计算,这些应用场景的共同之处是,不同计算阶段之间会重用中间结果,即一个阶段的输出结果会作为下一个阶段的输入。但是,目前的MapReduce框架都是把中间结果写入到HDFS中&…...
day06(单片机高级)PCB设计
目录 PCB设计 PCB设计流程 元器件符号设计 原理图设计 元器件封装设计 元器件库使用 PCB设计 目的:学习从画原理图到PCB设计的整个流程 PCB设计流程 元器件符号设计 元器件符号:这是电子元器件的图形表示,用于在原理图中表示特定的元器件。例…...
[Redis#2] 定义 | 使用场景 | 安装教程 | 快!
目录 1. 定义 In-memory data structures 在内存中存储数据 2. 优点!快 Programmability 可编程性 Extensibility 扩展性 Persistence 持久化 Clustering 分布式集群 High availability 高可用性 ⭕快速访问的实现 3. 使用场景 1.Real-time data store …...
docker pull命令拉取镜像失败的解决方案
docker pull命令拉取镜像失败的解决方案 简介: docker pull命令拉取镜像失败的解决方案 docker pull命令拉取镜像失败的解决方案 一、执行docker pull命令,拉取镜像失败 报错信息:error pulling image configuration: Get https://produc…...
漫步北京小程序构建智慧出行,打造旅游新业态模式
近年来,北京市气象服务中心持续加强推进旅游气象服务,将旅游气象监测预警基础设施纳入景区配套工程,提升气象和旅游融合发展水平,服务建设高品质智慧旅游强市。 天气条件往往影响着旅游景观的体验,北京万云科技有限公…...
DNS域名解析服务器
一、dns简介及域名 DNS(Domain Name System) : 作为将域名和IP地址相互映射的一个分布式数据库,能便捷互联网的访问。使用53端口,通常以UDP较快的数据传输协议来查询,如果没有查询到,将再次启动TCP重新查询,两者同时启…...
MySQL数据存储详解
1. MySQL 的数据存放位置 当我们在 MySQL 数据库中创建一个表时,MySQL 会在数据库对应的文件夹下生成三个文件: 1.1 db.opt 文件 是什么: 每个数据库都有一个 db.opt 文件,这个文件保存了数据库的配置信息。作用: 记…...
Maven maven项目构建的生命周期 Maven安装配置 IDEA 配置 Maven
一,Maven的概述 Maven的作用:专门用于管理和构建Java项目的工具,它的主要功能有: 提供了一套标准化的项目结构提供了一套标准化的构建流程(编译,测试,打包,发布……)提…...
和为 K 的子数组(java)
题目描述: 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1: 输入:nums [1,1,1], k 2 输出:2示例 2: 输入…...
关于Redux的学习(包括Redux-toolkit中间件)
目录 什么是 Redux ? 我为什么要用 Redux ? 我什么时候应该用 Redux ? Redux 库和工具 React-Redux Redux Toolkit Redux DevTools 拓展 一个redux小示例 代码示例(很有用): Redux 术语 Actions Reducers Store Dis…...
MIT 6.S081 | 操作系统 | Lab1: Xv6 and Unix utilities
Lab1: Xv6 and Unix utilities 文章目录 Lab1: Xv6 and Unix utilities实验任务1.启动XV6(easy)2.Sleep(easy)-练手的,就是熟悉一下怎么在xv6项目中加.c文件,生成可执行程序并进行测试的1.解析rm.c2.argc 如何被赋值3.Sleep代码4.makefile编辑5.通过make…...
04 - 尚硅谷 - MQTT 客户端编程
1.在Java中使用MQTT 1.1 Eclipse Paho Java Client 具体步骤: 1、创建一个Spring Boot项目,添加如下依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>…...
C语言基础学习:抽象数据类型(ADT)
基础概念 抽象数据类型(ADT)是一种数据类型,它定义了一组数据以及可以在这组数据上执行的操作,但隐藏了数据的具体存储方式和实现细节。在C语言中,抽象数据类型(ADT)是一种非常重要的概念&…...
蓝桥杯每日真题 - 第16天
题目:(卡牌) 题目描述(13届 C&C B组C题) 解题思路: 题目分析: 有 n 种卡牌,每种卡牌的现有数量为 a[i],所需的最大数量为 b[i],还有 m 张空白卡牌。 每…...