1 字符串
package main
// 字符串
func main() {
var a string = "hello world"
//1 按索引取值,只能取,不能改
fmt.Println(a[0]) //104 utf-8 对照的十进制 数字
//2 循环字符串 全英文 --->按字符/字节都一样,英文就只占一个字节
for i, v := range a {
fmt.Println(i, v, string(v)) //string() 强制类型转化
}
//3 迭代循环字符串 混着中文 --->按字符
var a string = "hello world 中国"
for i, v := range a {
fmt.Println(i, v, string(v))
}
//4 索引循环字符串 混着中文 --->按字节
for i := 0; i < len(a); i++ {
fmt.Println(i, a[i], string(a[i])) //中文部分会出现乱码
}
//5 字符串的长度
len:字节长度
utf8.RuneCountInString(s): 字符长度 //字符串中Rune的个数 Rune是int32 4个字节,所有字符最多4个字节
fmt.Println(len(a)) //18个字节
fmt.Println(utf8.RuneCountInString(a)) //14个字符
}
2 指针
//一、指针的含义
指针就是地址,获取变量的指针就是 获取变量的地址(首字节地址)
//1 获取变量的指针: &变量
var x int = 100
fmt.Println(&x) //0xc000016070
x=200 //变量相当于一个容器,为变量填充一个新值,容器的地址不变
fmt.Println(&x) //0xc000016070
// 2 通过指针操作变量值: *指针 表示对指针解引用,获取 指针指向的值
fmt.Println(*(&x)) //200
//通过变量的指针修改值
*(&x)=300
fmt.Println(*(&x)) //300
fmt.Println(x) //300
// 3 指针的类型: *值类型 eg: 变量x的类型为int,那指针&x的类型为 *int
变量的指针与变量名一样,都是指向首地址的 (首个字节单元的地址)
故指针也必须有类型,才能在取到首地址后,根据类型的大小规定,取出变量值 后续的内容
var x int = 100
var y string = "hello"
fmt.Printf("%T", &x) //输出类型:*int
fmt.Printf("%T", &y) //输出类型:*string
//二、指针变量 常用这个,操作更清晰
指针变量是 存储 变量内存地址 的变量 //将指针(地址)保存到一个变量中
& 放在变量前,表示取出变量的指针(内存地址)
* 放在类型前,表示该指针变量的类型,也就是该指针的类型 //指针变量 定义时使用
是在指针 指向的值 的类型 前加*
是 指向这个类型(指向的值 的类型) 的 指针
eg: 变量x的类型为int,那指针变量p(就是指针&x)的类型为 *int
* 放在指针变量前,表示解引用,会反解出指针(地址)指向的值 //通过指针变量,获取另一个变量 指针的值
package main
import "fmt"
func main() {
//指针变量:使用一个新变量 存 变量a 的内存地址,该新变量就是指向a的指针
//1 取一个变量a的内存地址 借助'&'
var a int=100
var p *int= &a //定义指针变量p
//有了指针变量p,*p就是*(&x),即*(变量x的地址),操作将会更加清晰
fmt.Println(p) //p的值为变量x的地址:0xc000016070
fmt.Println(*p) //*p即*(&x),结果为:100
fmt.Println(&p) //指针变量p本身也肯定是有地址的:0xc00000e030
//2 开启套娃
var a =100
var p *int=&a
fmt.Println(a) //变量a的值 : 10
fmt.Println(p) //指针变量p : 变量a的指针
fmt.Println(*p) //解引用,把p指向的真正值打印出来,a --> 10
var p1 **int=&p
//p1 :=&p
fmt.Println(p1) //指针变量p1 : 指针变量p的指针
var p2 ***int=&p1
//p2:=&p1
fmt.Println(p2) //指针变量p2 : 指针变量p1的指针
fmt.Println(***p2) //***p2 ---> **(*p2) ---> **p1 ---> *(*p1) ---> *p ---> 100
//3 指针的零值 指针是引用类型 零值为nil
var p *int
fmt.Println(p) //<nil>
//4 指针 当做函数参数传递时,会影响原来的值
var a =100
var p *int=&a
test1(p) //101
fmt.Println(a) //101
//5 不要向函数传递数组的指针,而应该使用切片
因为传递函数参数时,参数是数组的指针 的话
若每次传递数组的长度不一定,函数中参数类型中 数组长度需要每次修改
var a [3]int=[3]int{1,2,3}
var b [5]int=[5]int{1,2,3}
test2(&a) //若换成b数组指针 &b,则函数test2 参数的类型也要修改
fmt.Println(a)
test3(a[:]) //参数为切片时,就比较统一,不用修改
fmt.Println(a)
//6 指针数组 和 数组指针
//6.1 指针数组: 是数组,放指针的数组
var a =10
var b =11
var c =12
var p1 [3]*int=[3]*int{&a,&b,&c}
fmt.Println(p1) //[0xxx1 0xxx2 0xxxx3]
fmt.Println(*p1[0]) //10
//6.2 数组指针: 是指针变量,指向数组的指针
var a [3]int=[3]int{1,2,3}
var p2 *[3]int=&a
fmt.Println(p2) //&[1 2 3] 就是a数组的指针(地址)
}
func test1(p *int) {
*p+=1
fmt.Println(*p) //101
}
func test2(p *[3]int) {
(*p)[0]=999
fmt.Println(*p)
}
func test3(p []int) {
p[0]=999
fmt.Println(p)
}
3 结构体
//含义
是用户自定义的 类型,表示若干个字段的集合
---> python面向对象的类:属性和方法的集合
---> 结构体是python面向对象中类 概念的一半,只有属性,没有方法
//使用场景
有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体
package main
import ("fmt")
//1 定义结构体
type Person struct {
name string
age uint8
hobby string
}
//eg: 定义一个Hobby结构体
type Hobby struct {
//hobbyName string
//hobbyId int
string //匿名字段:字段没有名字,实则以类型作为字段名字
int
}
func main() {
//2 使用结构体
var p Person
//定义并初始化
var p Person=Person{"lqz",19,"篮球"} //按位置初始化,有几个字段,就要传几个
var p Person=Person{name: "lqz", age: 19} //按关键字初始化,可以只传几个参数
fmt.Println(p) //{lqz 19 篮球}
//3 使用结构体--赋值
p.name="lqz"
p.age=19
p.hobby="篮球"
fmt.Println(p.name)
//4 匿名结构体 没有type和名字的结构体
---> 只能定在函数内部使用,定义在外部,又没有名字,函数中咋使用尼
---> 把多个属性放到一个变量中,只使用一次
var p1= struct{
name string
age int
}{"egon",19}
var p1= struct{
name string
age int
}{age:19}
fmt.Println(p1)
//5 结构体的零值 值类型: 字段的零值
var p Person=Person{"lqz",19,"篮球"}
//值类型传递函数 原来结构体的值不会受影响
test1(p) //{刘亦菲 19 篮球}
fmt.Println(p) //{lqz 19 篮球}
//通过传递 结构体的指针,修改原来结构体的值
test2(&p) //&{刘亦菲 19 篮球}
fmt.Println(p) //{刘亦菲 19 篮球}
//6 结构体 大小写字母开头的含义
若在其他包,使用该结构体,注意结构体内的字段,也需要大写开头
//定义使用 package1包下 的 Person结构体
//var p package1.Person=package1.Person{"lqz",19}
var p =package1.Person{"lqz",19} //推导模式,少些变量的类型
var p package1.Person
fmt.Println(p.Name)
fmt.Println(p)
//7 结构体的指针
//var p *Person = &Person{"lqz",19}
var p = &Person{"lqz",19} //p 为 Person结构体 的 指针变量
p.Name="egon" //结构体的指针,可以不解引用,直接使用到 结构体
fmt.Println(p) //&{egon 19}
//8 匿名字段: 字段没有名字,以类型作为字段名 故类型不能重复
h :=Hobby{"篮球",1} //按位置传
h :=Hobby{string:"篮球",int:1} //按关键字传
fmt.Println(h.string) //篮球
fmt.Println(h.int) //1
//9 结构体嵌套: 结构体中套结构体
/* 应当定义在main函数外面
type Person struct {
name string
age uint8
hobby Hobby
}
type Hobby struct {
hobbyName string
hobbyId int
}
*/
p := Person{}
p := Person{name:"lqz",age:19,hobby:Hobby{"篮球",1}}
fmt.Println(p.hobby.hobbyName) //篮球
//10 结构体嵌套 + 匿名字段
/* 应当定义在main函数外面
type Person struct {
name string
age uint8
hobby Hobby
}
type Hobby struct { //1.Hobby结构体为匿名字段
string
int
}
*/
p := Person{name:"lqz",age:19,hobby:Hobby{"篮球",1}}
fmt.Println(p.hobby.string)
-----------------------------------------------------
/* 应当定义在main函数外面
type Person struct { //2.Person结构体中 Hobby为匿名字段
name string
age uint8
Hobby
}
type Hobby struct {
hobbyName string
hobbyId int
}
*/
p := Person{name:"lqz",age:19,Hobby:Hobby{"篮球",1}} //按关键字传
p := Person{"lqz",19,Hobby{"足球",2}} //按位置传
fmt.Println(p.Hobby.hobbyName) //p.Hobby 类似于面向对象的super()
fmt.Println(p.hobbyName) //字段提升 提升到最外层
//结构体嵌套 + 匿名字段: 实现了面对对象的继承
当Hobby为匿名字段时,类似于继承 Person为子类,Hobby为父类
p.hobbyName 类似于对象.属性 从自身类Person找不到,就去父类Hobby找
p.Hobby 类似于面向对象的super() 指名道姓的 去父类中找
//11 导出结构体和字段 根据大小写开头,决定是否在别的包内可以用
//12 结构体相等性
-如果它的每一个字段都是可比较的,则该结构体也是可比较的
若两个结构体变量的对应字段相等,则这两个变量也是相等的
-如果结构体中有不可比较的字段,结构体就不能比较 //引用类型字段不可比较
p1:=Person{name:"lqz",age:18}
p2:=Person{name:"lqz",age:19}
fmt.Println(p1==p2) //true
}
func test1(p Person) {
p.name="刘亦菲"
fmt.Println(p)
}
func test2(p *Person) {
//如果是结构体的指针,可以不用解引用,直接使用到 结构体
p.name="刘亦菲" // 等于 (*p).name="刘亦菲"
fmt.Println(p)
}
标签:04,Person,int,fmt,var,Println,Go,指针
From: https://www.cnblogs.com/Edmondhui/p/17172066.html