go语言之字符串、指针、数组、切片、结构struct、面向对象
一: 字符串
概述:
Go 语言将字符串作为 种原生的基本数据类型,字 符串的初始化可以使用字符串字面量。
(1)字符串是常量,可以通过类 数组 索引访问其字节单元,但是不能修改某个字节的值
(2)宇符串转换为切片[]byte( 要慎用,尤其是当数据量较大时(每转换一次都需复制内容)
a := ” hello, world !”
b : = []byte (a)
(3)字符串尾部不包含 NULL 字符
(4)字符串类型底层实现是一个二元的数据结构,一个是指针指向字节数组的起点,另一个是长度 (5)基于字符串创建的切片和原字符串指向相同的底层字符数组 一样不能修改 对字符
串的切片操作返回的子串仍然是由in ,而非 slice a := ” hello, world !
b :=a[: ]
c :=a [:2]
d :=a [:)
( )字符串和切片的转换字符串可以转换为字节数组,也可以转换为 Unicode 的字数组。
( )字符串的运算。
示例:
package main import (
"bytes"
"fmt"
"strconv"
"strings"
"time"
) func main() {
fmt.Println("字符串测试") fmt.Println("字符串转化")
//获取程序运行的操作系统平台下 int 类型所占的位数,如:strconv.IntSize。
//strconv.IntSize fmt.Println("将字符串转换为 int 型。")
var trastr01 string = ""
traint01, err_tra := strconv.Atoi(trastr01)
if err_tra != nil {
fmt.Println(err_tra)
} else {
fmt.Println(traint01)
}
fmt.Println("将字符串转换为 float64 型")
var trastr02 string = "100.55"
trafloat01, err_float := strconv.ParseFloat(trastr02, )
if err_float != nil {
fmt.Println(err_float)
} else {
fmt.Println(trafloat01)
}
trastr03 := strconv.Itoa()
fmt.Println("int 转字符安 " + trastr03) var str01 string = "hello,world"
str02 := "你好,世界"
fmt.Println(str01)
fmt.Println(str02) // //字符串比较
com01 := strings.Compare(str01, str02)
if com01 == {
fmt.Println("相等")
} else {
fmt.Println("不相等 " + string(com01))
}
fmt.Println(com01) //查找 包含
var isCon bool = strings.Contains(str01, "hello")
fmt.Println(isCon) //true //查找位置
var theIndex int = strings.Index(str01, ",")
fmt.Println(theIndex) //
fmt.Println(strings.Index(str01, "haha")) //不存在返回-1 lastIndex := strings.LastIndex(str01, "o")
fmt.Println("在字符串中最后出现位置的索引 " + strconv.Itoa(lastIndex)) //7
//-1 表示字符串 s 不包含字符串 //统计给定子串sep的出现次数, sep为空时, 返回1 + 字符串的长度
fmt.Println(strings.Count("cheeseeee", "ee")) //
fmt.Println(strings.Count("five", "")) // 5 // 重复s字符串count次, 最后返回新生成的重复的字符串
fmt.Println("hello " + strings.Repeat("world ", )) fmt.Println("替换")
// 在s字符串中, 把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换
var str03 string = "/Users//Documents/GOPatch/src/MyGO/config/TestString/"
str04 := strings.Replace(str03, "/", "**", -)
str05 := strings.Replace(str03, "/", "**", ) fmt.Println(str04) //**Users****Documents**GOPatch**src**MyGO**config**TestString**
fmt.Println(str05) //**Users****Documents**GOPatch/src/MyGO/config/TestString/ fmt.Println("删除字符串的开头和尾部")
fmt.Println("删除两头的/ = " + strings.Trim(str03, "/")) //Users//Documents/GOPatch/src/MyGO/config/TestString
fmt.Println("删除左边的/ = " + strings.TrimLeft(str03, "/")) //Users//Documents/GOPatch/src/MyGO/config/TestString/
//还有 TrimRight str06 := strings.TrimSpace(" hello hao hao hao ")
fmt.Println("删除开头末尾的空格 =" + str06) //'hello hao hao hao' fmt.Println("大小写")
str07 := "hello hao hao hao"
fmt.Println(strings.Title(str07)) //Hello Hao Hao Hao
fmt.Println(strings.ToLower(" Hello Hao Hao Hao")) // hello hao hao hao
fmt.Println(strings.ToUpper(str07)) //HELLO HAO HAO HAO //前缀 后缀
fmt.Println(strings.HasPrefix("Gopher", "Go")) // true
fmt.Println(strings.HasSuffix("Amigo", "go")) // true fmt.Println("字符串分割")
fieldsStr := " hello it's a nice day today "
//根据空白符分割,不限定中间间隔几个空白符
fieldsSlece := strings.Fields(fieldsStr)
fmt.Println(fieldsSlece) //[hello it's a nice day today] for i, v := range fieldsSlece {
fmt.Printf("下标 %d 对应值 = %s \n", i, v)
}
for i := ; i < len(fieldsSlece); i++ {
fmt.Println(fieldsSlece[i])
} //根据特定字符分割
slice01 := strings.Split("q,w,e,r,t,y,", ",")
fmt.Println(slice01) //[q w e r t y ]
fmt.Println(cap(slice01)) //7 最后多个空""
for i, v := range slice01 {
fmt.Printf("下标 %d 对应值 = %s \n", i, v)
} //拼接
//Join 用于将元素类型为 string 的 slice, 使用分割符号来拼接组成一个字符串:
var str08 string = strings.Join(fieldsSlece, ",")
fmt.Println("Join拼接结果=" + str08) //hello,it's,a,nice,day,today fmt.Println("------------对比字符串拼接效率----------------")
var buffer bytes.Buffer start := time.Now()
for i := ; i < ; i++ {
buffer.WriteString("test is here\n")
}
buffer.String() // 拼接结果
end := time.Now()
fmt.Println("Buffer time is ", end.Sub(start).Seconds()) start = time.Now()
str := ""
for i := ; i < ; i++ {
str += "test is here\n"
}
end = time.Now()
fmt.Println("+= time is ", end.Sub(start).Seconds()) start = time.Now()
var sl []string
for i := ; i < ; i++ {
sl = append(sl, "test is here\n")
}
strings.Join(sl, "")
end = time.Now()
fmt.Println("Join time is", end.Sub(start).Seconds())
/*
Buffer time is 0.00388283
+= time is 11.730007558
Join time is 0.016644653
*/ }
复合类型数据结构
基本复合数据类型有:指针、数组、切片、字典( map )、通道、结构和接口
* pointerType //指针类型使用*后面跟其指向的类型名
[n] elementType ///数纽类型使用[]后面跟数纽元素类型来表示, n表示该数组的长度
[] elementType //切片类型使用[] 后面跟切片元素类型来表示
map [keyType] valueType //map类型使用map[键类型]值类型来表示
chan valueType //通道使用chan后面跟通道元素类型表示
interface{ //接口类型 interface{} 将各个方法括起来
method1(inputParams)(returnParams)
method2(inputParams) (returnParams)
)
二:指针
概述:
指针声明类型为*T,多指针为**T
通过变量名前加&来获取变量的地址
1)在赋值语句中,*T出现在”=“ 左边表示声明,*T出现在”=“右边表示取指针指向的值(varName)
var a=
p := &a //*p和a的值都是11
2)结构体指针访问结构体字段然仍使用”.“ 点操作符
import "fmt" type User struct {
name string
age int
}
func main(){
andes := User{
name: "andes",
age: ,
}
p := &andes
fmt.Println(p.name) //p.name 通过“.”操作符访问成员变量
}
指针的使用
package main import "fmt" func main() {
// 声明变量
var a int =
// 声明指针
var ip *int
// 指针变量的存储
ip = &a
fmt.Printf("a变量地址是:%x\n", &a)
//指针变量存储的地址
fmt.Printf("ip变量存储的指针地址:%x\n", ip)
//使用指针访问值
fmt.Printf("*ip变量的值:%d\n", *ip)
}
3)go不支持指针运算
Go 由于支持垃圾回收,如果支持指针运算,则会给垃圾回收的 现带来很多不
a :=
P := &a
p++ // 不允许,报 non-numeric type *int 错误
4)函数中允许返回局部变量的地址
Go 编译器使用“战逃逸 机制将这种局部变量的空间分配在堆上
package main import "fmt" func sum (a , b int) *int {
sum := a + b
return &sum //允许, sum会分配在heap上
}
func main(){
fmt.Println(sum(,)) //打印内存地址
}
指针练习
程序获取一个int变量num的地址并打印
将num的地址赋给指针ptr,并通过ptr去修改num的值
package main
import "fmt"
func main(){
//定义变量
var num int =10
fmt.Println(&num)
//定义指针
var ptr *int
//指针赋值
ptr = &num
//根据指针修改值
*ptr=20
fmt.Println(num)
}
三: 数组
概述:
数组的类型名是 [n]emetType ,其中n是数组长度, elementType 是数组元素类型
数组一般在 创建时通过字面量初始化,单独声明一个数组类型变量而不进行初始化是没有意义的。
1)数组初始化
a : = []int {,,} //指定长度和初始化字面量
a : = [ . . . ]int{l , , } //不指定长度,但是由后面的初始 列表数量来确定其长度
a : = []int{l : l , : ) // 指定总长度,并通过索引值进行初始化,没有初始化元素时使用类型默认值
a : =[ ...}int{l :, : ) //不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元 被初始化为类型的零值
2)数组的特点:
)数组创建完长度就固定了,不可以再追加元素。
)数组是值类型的,数组赋值或作为函数参数都是值拷贝。
)数组长度是数组类型的组成部分,[]int 和[]int 表示不同的类型。
)可以根据数组创建切片
3) 数组相关操作
1 数组元素的访问
package main import "fmt" func main() {
a :=[...]int{,,}
b := a[]
for i,v :=range a{
fmt.Println(i,v)
fmt.Println(b)
}
}
2 数组切片的长度
package main import "fmt" func main(){
a := [...]int{,,}
alengh :=len(a)
for i :=; i<alengh; i++{
fmt.Println(a) //[1 2 3]
fmt.Println(alengh) //3 数组长度
fmt.Println(i) //2 索引值
}
}
四:切片
概述:
Go 语言的数组的定长性和值拷贝限制了其使用场景, Go 提供了另一种数据类型 lic (中文为切片),
这是 种变长数组,其数据结构中有指向数组的指针,所以是 种引用类型
package main import "unsafe" func main(){
type slice struct {
arry unsafe.Pointer
len int
cap int //cap()函数返回的是数组切片分配的空间大小
}
}
Go 为切片维护 个元素一一指向底层数组的指针、切片的元素数量和底层数组的容量。
切片的相关操作
1 切片的创建:
1)由数组创建
语法:
array[b:c],array表示数组名;b表示开始索引,可以不指定,默认是0;c表示结束索引,可以不指定,默认是len(array),数组长度,
package main
import (
"fmt"
)
func main(){
//创建有7个int类型元素的数组
var array = [...]int{,,,,,,}
s1 := array[:]
s2 := array[:]
s3 := array[:]
fmt.Println("%v\n",s1) // [0 1 2 3]
fmt.Println("%v\n",s2) // [0 1 2 3]
fmt.Println("%v\n",s3) // [2 3 4 5 6]
}
2)通过内置函数make创建切片
注意:由make创建的切片各元素被默认初始化为切片元素类型的零值
package main import "fmt" func main(){
//len=10,cap=10 创建数组a
a := make([]int,)
//len=10,cap=5 创建数组b
b := make([]int,,)
fmt.Printf("%v\n",a) //[0 0 0 0 0 0 0 0 0 0]
fmt.Printf("%v\n",b) //[0 0 0 0 0 0 0 0 0 0]
}
注意:直接声明切片类型变量是没有意义的
func main(){
var a []int
fmt.Printf("%v\n",a) //结采为 []
}
此时切片a底层的数据结构
3)切片支持的操作
内置函数 len()返回切片长度
内置函数 cap()返回切片底层数组容量。
内置函数 ppend()对切片追加元素。
内置函数 copy() 用于 一个切片
package main import (
"fmt"
) func main() {
a := [...]int{,,,,,,}
b := make([]int,,)
c := a[:]
fmt.Println(b) //[0 0]
fmt.Println(len(b)) //
fmt.Println(cap(b)) //
b = append(b,) //切片尾部追加元素 1
fmt.Println(b) //[0 0 1]
fmt.Println(len(b)) //
fmt.Println(c) //[0 1 2]
fmt.Println(cap(b)) // b = append(b,c...)
fmt.Println(b) //[0 0 1 0 1 2]
fmt.Println(len(b)) //
fmt.Println(cap(b)) // d := make([]int,,)
copy(d,c) //copy只会复制d和c中长度最小的
fmt.Println(d) //[0 1]
fmt.Println(len(d)) //
fmt.Println(cap(d)) //
}
示例二
package main import "fmt" func main() {
// 定义数组
arr := [...]int{,,,,,,,}
// 切片取值
fmt.Println("arr[2:6]=",arr[:])
fmt.Println("arr[:6]=",arr[:])
fmt.Println("arr[2:]=",arr[:])
fmt.Println("arr[:]=",arr[:])
}
l内建函数append():向切片尾部添加数据
package main import "fmt" func main() {
//空切片
var s1 []int
s1=append(s1,,)
s1=append(s1, ,,)
fmt.Println("s1=" ,s1) //s1= [2 3 4 5 6]
//创建指定大小的切片
s2 := make([]int,) //创建长度为5的并初始化为0的切片
s2 =append(s2,)
fmt.Println(s2) //[0 0 0 0 0 6]
//创建并初始化切片
s3 := []int{,,}
s3 =append(s3,,)
fmt.Println(s3) //[1 2 3 4 5]
}
示例2
package main import (
"fmt"
) func main() {
//1 go 语言切片是对原数组的映射,并没有创建一个真正的切片
//定义数组
arr :=[...]int{,,,,,,,}
//取切片
s1 :=arr[:]
fmt.Println(s1) //[2 3 4 5] s2 := s1[:]
fmt.Println(s2) //[5 6]
s3 := append(s2,)
fmt.Println(s3) //[5 6 10]
s4 :=append(s3,)
fmt.Println(s4) //[5 6 10 11]
s5 :=append(s4,)
fmt.Println(s5) //[5 6 10 11 12]
}
内置函数copy()
package main import "fmt" func main() {
//go语言切片是对原数组的映射,并灭有创建一个真正的切片
//定义数组
data := [...]int{,,,,,,,,,}
//取切片 8,9
s1 := data[:]
s2 := data[:]
//将后面切片元素,拷贝到前面切面里面
//copy()是从前往后添加并覆盖
copy(s2,s1)
fmt.Println(s2) //[8 9 2 3 4]
fmt.Println(data) // [8 9 2 3 4 5 6 7 8 9]
}
go语言切片实际上是view操作
package main import (
"fmt"
) func main() {
//1go语言切片是对原数组的映射,并没有创建一个真正的切片
//定义数组
arr :=[...]int{,,,,,,}
//去切片
s1 :=arr[:]
//修改值
s1[] =
fmt.Println(s1) //[100 4 5 6 7]
fmt.Println(arr) //[1 2 100 4 5 6 7]
fmt.Println()
//go 语言切片美誉取到的位置,可以反向延申,不可向前延申
s3 :=arr[:]
fmt.Println(s3) //[100 4 5 6]
s4 :=s3[:]
fmt.Println(s4) //[6 7]
//容量大小
fmt.Println("s3=%v,len(s3)=%d,cap(s3)=%d\n",s3,len(s3),cap(s3))
// [100 4 5 6] 4 5
}
4)字符串切片的相互转换
package main
import "fmt"
func main(){
str := "hello,世界" //通过字符串字面量初始化 个字符串 str
a := []byte(str) //将字符串转换为[]byte 类型切片
b := []rune(str) //将字符串转换为[]rune 类型切片
fmt.Println(a) //[104 101 108 108 111 44 228 184 150 231 149 140]
fmt.Println(b) //[104 101 108 108 111 44 19990 30028]
}
五: map
概述:
go语言内置的字典类型叫map。map的类型格式:
map[K]T,其中K可以是任意可以进行比较的类型
T值类型。map也是一种引用类型
1)map的创建
package main import "fmt" func main() {
//1 创建map
var m1 map[int]string
fmt.Println(m1==nil)
//赋值报错因为是空的
//m1[1]="xxx"
//2 :=
m2 :=map[int]string{}
m3 :=make(map[int]string)
fmt.Println(m2,m3)
fmt.Println(m2[])
//3 指定容量
m4 :=make(map[int]string,)
fmt.Println(m4)
fmt.Println(m4[])
}
示例
package main import "fmt" func main(){
ma := map[string]int { "a": , "b": }
fmt.Println(ma ["a"]) //
fmt.Println(ma ["b"]) //
}
map初始化
package main import (
"fmt"
) func main() {
//1 定义并初始化
var m1 map[int]string= map[int]string{:"hello",:"world"}
fmt.Println(m1)
//2 自动推断类型
m2 := map[int]string{:"hello",:"world"}
fmt.Println(m2)
}
2)使用内置的make函数创建
package main import "fmt" func main(){
//make(map[K]T) //map 容量使用默认位
//make(map[K]T,len) //map 的容量使用给定 len值
mpl := make(map[int]string)
mp2 := make(map[int]string,)
mpl[l] = "tom" mp2[] = "pony"
fmt.Println(mpl[l] ) //tom
fmt.Println(mp2[] ) //pony
}
3)map支持的操作
map 的单个键值访问格式为mapName[key], 更新某个key 值时mapName[key]等号左边,访某个key的值时 mapName[key]放在等号的右边。
可以使用range遍历一个map类型变量,但是不保证每次迭代 元素的顺序。
删除map中的某个键值用如下语法: delete(mapName,key)。 delete是内置函数用来删除 map 中的某个键值对
可以使用内置的len()函数返回map中的键值对数量。
package main import (
"fmt"
) func main(){
mp := make(map[int]string)
mp[1] = "tom"
mp[1] = "pony"
mp[2] = "jsky"
mp[3] = "andes"
delete(mp,3)
fmt.Println(mp[1]) //pony
fmt.Println(len(mp)) //2
for k,v := range mp{
fmt.Println("key",k,"value",v)
//key 2 value jsky
//key 1 value pony
}
}
示例2
package main import (
"fmt"
) func main() {
m1 :=map[int]string{:"湖南小小鲜肉",:"成都小妹妹"}
m1[]="山西肉蒲团"
m1[] ="东莞小姐姐"
fmt.Println(m1) //map[0:山西肉蒲团 1:湖南小小鲜肉 2:成都小妹妹 3:东莞小姐姐]
//make()
m2 :=make(map[int]string,)
m2[]="山西挖煤团"
m2[]="内蒙放羊团"
fmt.Println(m2) //map[0:山西挖煤团 1:内蒙放羊团]
fmt.Println(m2[],m2[]) // 山西挖煤团 内蒙放羊团
}
遍历与删除
package main import (
"fmt"
) func main() {
m1 := map[int]string{:"肉蒲团",:"黄梅"}
m1[] = "东京卫视"
m1[] = "北京卫视"
fmt.Println(m1) //map[1:东京卫视 2:黄梅 3:北京卫视]
//make()
m2 :=make(map[int]string,)
m2[]="东京热"
m2[]="小泽玛丽呀"
fmt.Println(m2) //map[0:东京热 1:小泽玛丽呀]
fmt.Println(m2[],m2[]) // 东京热 小泽玛丽呀
//map遍历
for k := range m1{
fmt.Println("%d----->%s\n",k,m1[k])
/*
%d----->%s
1 东京卫视
%d----->%s
2 黄梅
%d----->%s
3 北京卫视
*/
//判断map里面有没有此键
value,ok := m1[]
fmt.Println("value1=",value,",ok1=",ok) //value1= ,ok1= false
}
//删除delete
delete(m1,)
fmt.Println(m1) //map[1:东京卫视 3:北京卫视]
}
注意:
Go 内置的map不是并发安全的,并发安全的map可以使用标准包sync中的map
不要直接修改map value内某个元素的值,如果想修改 map 的某个键值,则必须整体赋值
package main import "fmt" type User struct {
name string
age int
}
func main(){
ma := make(map[int]User)
andes := User{
name:"andes",
age :,
}
ma[] = andes //必须整体赋值
//ma[1].age=19 //error ,不能通过map引用直接修改
andes.age=
fmt.Printf("%v\n",ma) //map[1:{andes 18}]
fmt.Println(andes.age) //
}
六: struct(结构)
概述:由多个不同类型的元素组合而成,有两层含义:
struct 结构中的类型可以是任意类型
struct 的存储空间是连续的其字段按照声明时的顺序存放(字段之间有对齐的要求)
struct有两种形式:
struct字面量 2使用type声明自定义struct类型
1 struct类型字面量
struct类型字面量的声明格式如下
struct {
FeildName FeildType //字段名 字段类型
FeildName FeildType
FeildName FeildType
}
2 自定义struct类
type TypeName struct {
FeildName Fe ldType //字段名 字段类型
FeildName FeildType
FeildName FeildType
}
type自定义类型关键字,不但支持struct类型的创建,还支持任意其他任意子定义类型的创建
3 struct 类型变量的初始化
package main import "fmt" //定义学生结构体
type Student struct {
id int
name string
sex byte
age int
addr string
}
func main(){
//1顺序初始化
//字符串用双引号,字符用单引
var s1 Student = Student{,"约汉",'f',,"xx"}
fmt.Println(s1) //{1 约汉 102 18 xx}
s2 :=Student{,"Jack",'m',,"yy"}
fmt.Println(s2) //{2 Jack 109 20 yy}
//2 指定初始化
s3 :=Student{id:,age:}
fmt.Println(s3) //{3 0 20 }
//3 结构体作为指针变量初始化
var s4 *Student = &Student{,"撸死",'m',,"jd"}
fmt.Println(s4) //&{4 撸死 109 24 jd}
//指针访问变量
//go底层会先判断传的是值还是指针类型
//若是指针类型,go会将s4 id替换(*s4).id
fmt.Println((s4).id) //
fmt.Println(s4.id) // s5 :=&Student{,"xx",'f',,"sz"}
fmt.Println(s5) //&{5 xx 102 27 sz}
}
示例
package main import "fmt"
func main() {
type Person struct {
name string
age int
}
type student struct {
*Person
Number int
} //按照类型声明顺序,逐个赋值
//不推荐这种初始化方式,一旦struct增加字段,则整个初始化语句会报错
a := Person{"Tom", }
//推荐这种使用Feild名字的初始化方式,没有指定的字段则默认初始化为类型的零值
P := &Person{
name: "tata",
age: ,
}
s := student{
Person: P,
Number:,
}
fmt.Println(a) //{Tom 21}
fmt.Println(P) //&{tata 12}
fmt.Println(s) //{0xc000078420 110}
}
4 结构体参数
结构体可以作为函数参数传递
结构体作为指针或非指针效果不一样
package main import (
"fmt"
) type Student struct {
id int
name string
sex string
age int
addr string
}
func tmpStudent(tmp Student) {
tmp.id=
fmt.Println("tmp=",tmp) //tmp= {250 zhangsan f 20 sz00}
}
func tmpStudent2(p *Student) {
p.id =
fmt.Println("tmp=",p) //tmp= &{249 zhangsan f 20 sz00}
}
func main() {
var s Student = Student{,"zhangsan","f",,"sz00"}
//传递非指针对象
tmpStudent(s)
fmt.Println("main s=",s) //main s= {1 zhangsan f 20 sz00}
//传递指针对象
tmpStudent2(&s)
fmt.Println("main s2=",s) // main s2= {249 zhangsan f 20 sz00}
}
七:面向对象
1 简介:
go语言对于面向对象的设计非常简洁而优雅
没有封装、继承、多态这些概念,但同样通过别的方式实现这些特性
1封装:通过方法实现
2继承:通过匿名字段实现
3多态:通过接口
2 匿名字段
go支持只提供类型而不写字段名的方式,也就是匿名字段,也称为嵌入字段
package main import "fmt" type Person struct {
name string
sex string
age int
}
//学生
type Student struct {
//匿名字段
Person
id int
addr string
}
func main() {
//1.顺序初始化
s1 :=Student{Person{"杰克","female",},,"sz"}
fmt.Println(s1) //{{杰克 female 18} 1 sz}
// 部分初始化
s2 := Student{Person: Person{name:"接客"}, id: }
fmt.Println(s2) // {接客 0} 2 }
}
同名字段情况
package main import (
"fmt"
) //人的结构体
type Person struct {
name string
sex string
age int
}
type Student struct {
//匿名字段
Person
id int
addr string
//和Person中的字段同名
name string
} func main() {
var s Student
s.name="约汉"
fmt.Println(s) //{{ 0} 0 约汉}
//默认是就近原则赋值
//若需要赋值上一层,需要显式调用
s.Person.name="杰克"
fmt.Println(s) //{{杰克 0} 0 约汉}
}
所有的内置类型和自定义类型都是可以作为匿名字段去使用
package main import ( "fmt"
) //人的结构体
type Person struct {
name string
sex string
age int
}
//自定义类型
type mystr string
//学生
type Student struct {
//结构体类型匿名字段
Person
//内置类型匿名字段
int
//自定义类型匿名字段
mystr
}
func main() {
s1 := Student{Person{"lisi","male",},,"bj"}
fmt.Println(s1) //{{lisi male 18} 1 bj}
fmt.Println(s1.name) // lisi
}
指针类型匿名字段
package main import (
"fmt"
) //人的结构体
type Person struct {
name string
sex string
age int
}
//学生
type Student struct {
//结构体类型的匿名字段
*Person
id int
addr string
}
func main() {
s1 := Student{&Person{"wwangwu","male",},,"sz"}
fmt.Println(s1) //{0xc000088300 1 sz}
fmt.Println(s1.name) // wwangwu
}
3 方法
在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数
这种带有接收者的函数,我们称为方法,本质上,一个方法则是一个和特殊类型关联的函数
方法的语法如下
func (接收参数名 接收类型) 方法名(参数列表)(返回值)
1可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法
2接收类型可以是指针或非指针类型
3为类型添加方法
基础类型作为接收者
package main import "fmt" type Myint int //定义方法,实现两个数相加
func Add(a,b Myint) Myint{
return a + b
}
func (a Myint) Add(b Myint) Myint{
return a + b
}
func main() {
var a Myint =
var b Myint=
//面向过程调用
fmt.Println("Add(a,b)",Add(a,b)) //Add(a,b) 2
//面向对象的调用
fmt.Println("a.Add(b)",a.Add(b)) //a.Add(b) 2 }
结构体作为接收者
package main import "fmt" type Person struct {
name string
sex string
age int
} //给Person添加方法
func (p Person) PrintInfo() {
fmt.Println(p.name, p.sex, p.age)
} func main() {
p := Person{"zhaoliu", "male", }
p.PrintInfo()
}
值语义和引用语义
package main import "fmt" type Person struct {
name string
sex string
age int
} //给成员赋值,引用语义
func (p *Person) SetInfoPointer() {
(*p).name = "tianqi"
p.sex = "female"
p.age =
} //值语义
func (p Person) SetInfoValue() {
p.name = "zhouba"
p.sex = "male"
p.age =
} func main() {
//指针作为接收者的效果
p1 := Person{"xxx", "male", }
fmt.Println("函数调用前=", p1)
(&p1).SetInfoPointer()
fmt.Println("函数调用后=", p1) //值作为接收者
p2 := Person{"yyy", "female", }
fmt.Println("函数调用前=", p2)
p2.SetInfoValue()
fmt.Println("函数调用后=", p2)
}
方法的继承
package main import "fmt" type Person struct {
name string
sex string
age int
} //为Person定义方法
func (p *Person) PrintInfo() {
fmt.Printf("%s,%s,%d\n", p.name, p.sex, p.age)
} //继承上面的方法
type Student struct {
Person
id int
addr string
} func main() {
p := Person{"xxx", "male", }
p.PrintInfo()
s := Student{Person{"yyy", "male", }, , "bj"}
s.PrintInfo()
}
方法的重写
package main import "fmt" type Person struct {
name string
sex string
age int
} //为Person定义方法
func (p *Person) PrintInfo() {
fmt.Printf("%s,%s,%d\n", p.name, p.sex, p.age)
} //继承上面的方法
type Student struct {
Person
id int
addr string
} //相当于实现了方法重写
func (s *Student) PrintInfo() {
fmt.Printf("Student:%s,%s,%d\n", s.name, s.sex, s.age)
} func main() {
p := Person{"xxx", "male", }
p.PrintInfo()
s := Student{Person{"yyy", "male", }, , "bj"}
s.PrintInfo()
//显式调用
s.Person.PrintInfo()
}
方法值和方法表达式
package main import "fmt" type Person struct {
name string
sex string
age int
} func (p *Person) PrintInfoPointer() {
//%p是地址,%v是值
fmt.Printf("%p,%v\n", p, p)
} func main() {
p := Person{"zhangsan", "male", }
//传统调用方式
p.PrintInfoPointer()
//go语义方法值特性
pFunc1 := p.PrintInfoPointer
pFunc1()
//go方法表达式特性
pFunc2 := (*Person).PrintInfoPointer
pFunc2(&p)
}
练习:创建属性的getter和setter方法并进行调用
package main import "fmt" //练习:创建属性的getter和setter方法并进行调用
type Dog struct {
name string
// 1公0母
sex int
} func (d *Dog) SetName(name string) {
d.name = name
} func (d *Dog) GetName() string {
return d.name
} //dog咬人的方法
func (d *Dog) bite() {
fmt.Printf("%s咬人了,起锅烧油", d.name)
} func test01() {
//创建dog对象
d := Dog{"二哈", }
d.bite()
} func main() {
test01()
}
注意:
new()和make()
new()用来分配内存,但与其他语言中的同名函数不同,它不会初始化内存,只会将内存置零
make(T)会返回一个指针,该指针指向新分配的,类型为T的零值,适用于创建结构体
make()的目的不同于new(),它只能创建slice、map、channel,并返回类型为T(非指针)的已初始化(非零值)的值
go语言之字符串、指针、数组、切片、结构struct、面向对象的更多相关文章
- C语言中的指针数组
C语言中的指针数组是什么,像 char *a[]={"ddd","dsidd","lll"}; 这里讲一下注意如果我们使用了a也就是首元素的 ...
- C++笔记--指针数组和结构
指针 类型为T*的变量能保存一个类型T对象的地址 Char c=‘a’:Char * p=& c://保存了c的地址 指针的操作一般都是间接的引用,就是相当于引用指针所指的对象. 0是一个特殊 ...
- C语言回顾-字符串指针
1.字符串指针 char *变量名="字符串内容"; char ch='b'; char *p1=&ch; char *str="C Language" ...
- c语言实现动态指针数组Dynamic arrays
c语言实现动态数组.其它c的数据结构实现,hashTable參考点击打开链接 treeStruct參考点击打开链接 基本原理:事先准备好一个固定长度的数组. 假设长度不够的时候.realloc一块区域 ...
- [C++学习历程]基础部分 C++中的指针数组和结构
作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/19938177 一.指针 对学习C++来说,指针是一项重要内容,以前,教 ...
- C语言中的指针数组和数组指针
代码: #include <iostream> using namespace std; int main(){ ]; ]; cout<<sizeof(a)<<en ...
- C语言的函数指针数组(好绕啊~看完这篇估计就通关了)
转自https://www.cnblogs.com/chr-wonder/p/5168858.html int *(*p(int))[3] 今天有人问这个是啥?我一看直接就懵逼了…… 下面做一些简单的 ...
- C语言深度剖析-----指针数组和数组指针的分析
指针数组和数组指针的分析 数组类型 定义数组类型 数组指针 这个不可能为数组指针,指向数组首元素 例 指针数组 例 main函数的参数 例 小结
- 嵌入式-C语言基础:指针数组(和数组指针区分开来)
指针数组:一个数组,若其元素均为指针类型的数据,称为指针数组,指针数组存放的是指针类型的数据,也就是指针数组的每个元素都存放一个地址.下面定义一个指针数组: int * p[4];//[]的优先级是比 ...
- c语言指针数组和结构体的指针
指向数组的指针,先初始化一个数组,使用传统方式遍历 void main() { ] = { ,,,, }; ; i < ; i++) { printf("%d,%x\n", ...
随机推荐
- PHP hebrev() 函数
实例 反向显示希伯来字符: <?phpecho hebrev("á çùåï äúùñâ");?>高佣联盟 www.cgewang.com 定义和用法 hebrev() ...
- luogu P4206 [NOI2005]聪聪与可可 期望dp 记忆化搜索
LINK:聪聪与可可 这道题的核心是 想到如何统计答案. 如果设f[i][j]表示第i个时刻... 可以发现还需要统计位置信息 以及上一次到底被抓到没有的东西 不太好做. 两者的位置都在变化 所以需要 ...
- Hadoop学习之NCDC天气数据获取
期望目的 下载<Hadoop权威教程>里用到的NCDC天气数据,供后续在此数据基础上跑mapred程序. 操作过程 步骤一.编写简单的shell脚本,下载数据文件到本地文件系统 已知NCD ...
- RNN神经网络产生梯度消失和梯度爆炸的原因及解决方案
1.RNN模型结构 循环神经网络RNN(Recurrent Neural Network)会记忆之前的信息,并利用之前的信息影响后面结点的输出.也就是说,循环神经网络的隐藏层之间的结点是有连接的,隐藏 ...
- 【FZYZOJ】细菌 题解(最短路)
题目描述 为了研究一种新型细菌(称它为S型细菌)的性质,Q博士将S型细菌放在了一个犹如迷宫一般的通道面前,迷宫中N个站点,每个站点之间以一种单向通道的形式连接,当然,也有可能某两个站点之间是互不联通的 ...
- FastAPI框架入门 基本使用, 模版渲染, form表单数据交互, 上传文件, 静态文件配置
安装 pip install fastapi[all] pip install unicorn 基本使用(不能同时支持,get, post方法等要分开写) from fastapi import Fa ...
- JAVA的基本程序设计结构<上>
一个简单的Java应用程序 public class FirstSample { public static void main(String[] args) { System.out.println ...
- three.js 着色器材质之变量(三)
这篇郭先生在练习一下着色器变量,在度娘上面或者官网上经常看到类似水波一样的效果,这篇就试着做一个这样的效果,顺便巩固一下顶点着色器和片元着色器,毕竟多多练习才能更好地掌握.效果如下图,在线案例请点击博 ...
- Java自学-图形界面 事件监听
Swing 如何进行事件监听 示例 1 : 按钮监听 创建一个匿名类实现ActionListener接口,当按钮被点击时,actionPerformed方法就会被调用 package gui; imp ...
- 轻轻松松学CSS:position
position属性表示元素的定位类型,在CSS布局中,position发挥着非常重要的作用,一些元素的布局就是用position完成的,鉴于此,本文结合一些小实例详细讲解一下. position属性 ...