字符串
# Go 语言中的字符串是一个字节(byte)切片 []byte 。把内容放在双引号””之间,我们可以创建一个字符串。让我们来看一个创建并打印字符串的简单示例
package main
import (
"fmt"
"unicode/utf8"
)
// 字符串
func main() {
// 1 介绍
var s string = "lqz-中国"
fmt.Println(s[0]) // 按下标取值---》但是不能改
fmt.Printf("类型是:%T\n", s[0]) // 按下标取值---》取到字节---》但是不能改
//2 不可变: 如果要改字符串---》转成字节数组(字节切片)---》修改完---》转成字符串
// 3 循环字节
for i := 0; i < len(s); i++ {
fmt.Println(string(s[i]))
}
//4 循环字符
for _, value := range s {
fmt.Println(string(value))
}
// 5 字符串长度:字节长度
fmt.Println(len(s))
//6 字符串长度:字符长度
fmt.Println(utf8.RuneCountInString(s))
//7 字节切片构造字符串
var b []byte = []byte{'a', 'b', 98}
fmt.Println(string(b))
//8 字符切片构造字符串
var r []rune = []rune{20013, '国', 98}
fmt.Println(string(r))
}
指针
指针是一种存储变量内存地址(Memory Address)的变量
![]()
package main
import "fmt"
// 指针
// 1 & (取地址符号)放在变量前,表示取这个变量的地址
// 2 * 放在类型前,表示指向这个类型的指针---》定义类型
// 3 * 放在变量前(指针类型变量),解引用--》把指针指向的值,解出来
func main() {
//1 指针基本使用---三句话
//var a int = 10
//
////var p = &a
//var p *int = &a
//fmt.Println(p) // 0xc00000a0c8
//
//var s = "lqz"
//var p1 *string = &s
//fmt.Println(p1)
//
//var arr = [3]int{5, 6, 7}
//var p2 *[3]int = &arr
//fmt.Println(p2) //内存地址---》显示成 &[5 6 7]
//
//// p 真正的指向了谁
//
//fmt.Println(*p)
//fmt.Println(*p1)
//fmt.Println(*p2)
// 2 指针的指针
//var a int = 10
//
//var p1 *int = &a
//
//var p2 **int = &p1
//
//var p3 ***int = &p2
//
//fmt.Println(p3)
//fmt.Println(p2)
//fmt.Println(p1)
//fmt.Println(*p3) // p2的值
//fmt.Println(*p2) // p1的值
//fmt.Println(*p1) // a的值 10
//
//fmt.Println(***p3) // a的值 10
//
// 3 指针零值---》引用---》如果不赋初值--》就是空指针---><nil>
// 所有引用类型的空值 :nil
// 所有值类型的零值:都是默认值 数字就是0,字符串就是 "" 布尔就是false
//var p1 *int
//fmt.Println(p1)
// 4 向函数传递指针参数
//var a = 100
//test001(&a)
//fmt.Println("外层", a) // a是多少?101
// 5 不要向函数传递数组的指针,而应该使用切片
//var arr = [3]int{9, 8, 7}
//test002(&arr)
//fmt.Println("外层", arr)
//
//var arr1 = [400]int{9, 8, 7}
//test003(arr1[:])
//fmt.Println("外层-层", arr1)
// 6 指针不允许运算-->c语言中指针能运算
// 7 指针数组【数组中放的是指针类型】和数组指针【指向数组的指针】
var arr = [3]int{9, 8, 7}
var p1 *[3]int = &arr // 数组指针【指向数组的指针】
fmt.Println(p1) // &[9,8,7]
var a, b, c = 99, 88, 77 // 指针数组
var p2 [3]*int = [3]*int{&a, &b, &c}
fmt.Println(p2) // [0x111,0x3212,0xasfasd]
}
func test001(p *int) {
fmt.Println(p) //内存地址
fmt.Println(*p) // 内存指向的值 100
(*p)++ // 对100 +1 101
fmt.Println(*p) // 101
}
func test002(p *[3]int) {
(*p)[0] = 999 // *p 解引用,解成数组---》取第0个位置,改成 999
fmt.Println(*p)
}
func test003(p []int) {
p[0] = 888 // 通过切片改值
fmt.Println(p)
}
结构体
# 什么是结构体?
结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。
例如,人有姓名,性别,年龄---》三个字段,放到一个结构体中,而不是把它定义成三个变量
# 结构体:就是面向对象中类的概念---》只有属性,没有方法
package main
import (
"fmt"
"go_day05/entity"
)
// 结构体--》用户定义的类型
// 1 ########定义结构体########
// 定义一个人结构体,有三个字段
//type Person struct {
// name string
// age uint
// gender string
//}
// 定义狗结构体---》匿名字段--》字段没有名字
//type Dog struct {
// string // 狗名字,不写
// uint
// age uint // 如果有两个类型一致,不能使用匿名字段
//}
// 10 结构体嵌套 结构体中套结构体
//type Cat struct {
// name string
// age uint
// // 爱好,结构体类型--》Hobby
// hobby Hobby
//}
//type Hobby struct {
// id int
// name string
//}
// 12 结构体嵌套+匿名字段
//type Cat struct {
// name string
// age uint
// Hobby // 匿名字段
//}
//type Hobby struct {
// id int
// name string
//}
func main() {
// 1 定义结构体
// 2 使用结构体--》定义一个Person类型变量---》操作
//var person Person // 定义,没有赋初值
//fmt.Println(person) // 如果是nil,表示它是引用类型,如果有默认值,他就是值类型---》值类型
// 3 修改和获取结构体的元素
//person.name = "彭于晏"
//person.age = 10
//person.gender = "女"
//fmt.Println(person)
// 4 打印人名
//fmt.Println(person.name)
// 5 定义并初始化
//var person1 Person = Person{"刘亦菲", 88, "女"} // 按位置,不能少
//var person2 = Person{name: "迪丽热巴"} // 按关键字,少传--》没传的默认零值
//fmt.Println(person1.name)
//person2.gender = "男"
//fmt.Println(person2.gender) // ""
// 6 结构体是值类型---》不初始化,也能使用---》当参数传递,再函数中修改了,会影响原来的吗? 不会
//var person1 Person = Person{"刘亦菲", 88, "女"}
//test004(person1)
//fmt.Println("外部:", person1)
// 7 如果想改原来的值--取地址
//var person1 *Person = &Person{"刘亦菲", 88, "女"}
//test005(person1)
//var person1 Person = Person{"刘亦菲", 88, "女"}
//test005(&person1)
//fmt.Println("外部:", person1)
// 8 匿名字段 --》结构体是一系列字段的集合---》字段可以没有名字
// 初始化狗结构体
//var dog Dog = Dog{"小奶狗", 30, 2} // 按位置赋值
//var dog Dog = Dog{string: "小奶狗", uint: 30, age: 2} // 按关键字赋值 -->如果是匿名字段--》类型名就是字段名
//fmt.Println(dog)
// 9 获取和修改匿名字段的值---》按类型名获取即可
//dog.string = "小奶奶狗"
//fmt.Println(dog.string)
// 10 结构体嵌套
// 11 结构体嵌套 初始化
//var cat Cat
//var cat Cat=Cat{"小野猫",4,Hobby{1,"篮球"}}
//var cat Cat=Cat{name:"小野猫",age:4,hobby: Hobby{1,"篮球"}} //关键字
//var cat Cat = Cat{name: "小野猫", age: 4, hobby: Hobby{id: 1, name: "篮球"}} //关键字
//fmt.Println(cat)
////拿到猫的爱好id
//fmt.Println(cat.hobby.name)
// 12 结构体嵌套+匿名字段---》字段提升
//var cat Cat = Cat{"小野猫", 4, Hobby{1, "篮球"}}
////var cat Cat = Cat{name: "小野猫", age: 4, Hobby: Hobby{id: 1, name: "篮球"}}
//fmt.Println(cat.Hobby.name)
//fmt.Println(cat.id) // cat 没有id--》因为Hobby是匿名字段--》把内部的字段提升到外层
//// cat 有name,hobby也有name ,字段会提升吗? 不会提升
//fmt.Println(cat.name)
// 有什么用?字段提升---》面向对象的继承---》Cat继承了Hobby---》cat.id-->自己没有--》直接拿到父类的属性
// 13 导出结构体字段---》使用entity包下的dog---》面向对象封装
// 无论是结构体还是字段,想在别的包使用,必须大写开头
var dog entity.Dog = entity.Dog{Name: "野狗"}
fmt.Println(dog.Name)
}
//func test004(person Person) {
// person.name = "xxxxx"
// fmt.Println(person)
//
//}
//
//func test005(person *Person) {
// (*person).name = "xxxxx"
// fmt.Println(*person)
//
//}
方法
# 方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器是可以在方法的内部访问的
# 函数 方法
方法-->特殊--》自动传值--》绑定给对象或类的
package main
import "fmt"
// 方法
type Fish struct {
name string
age uint
}
// 结构体绑定方法
func (fish Fish) getName() string {
return fish.name
}
func main() {
var fish Fish = Fish{"小金鱼", 1}
res := fish.getName() // 自动传值
fmt.Println(res)
}