GO.5——字符串,,指针,,结构体,,方法
# 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) }