一: 字符串

概述:
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、面向对象的更多相关文章

  1. C语言中的指针数组

    C语言中的指针数组是什么,像 char *a[]={"ddd","dsidd","lll"}; 这里讲一下注意如果我们使用了a也就是首元素的 ...

  2. C++笔记--指针数组和结构

    指针 类型为T*的变量能保存一个类型T对象的地址 Char c=‘a’:Char * p=& c://保存了c的地址 指针的操作一般都是间接的引用,就是相当于引用指针所指的对象. 0是一个特殊 ...

  3. C语言回顾-字符串指针

    1.字符串指针 char *变量名="字符串内容"; char ch='b'; char *p1=&ch; char *str="C Language" ...

  4. c语言实现动态指针数组Dynamic arrays

    c语言实现动态数组.其它c的数据结构实现,hashTable參考点击打开链接 treeStruct參考点击打开链接 基本原理:事先准备好一个固定长度的数组. 假设长度不够的时候.realloc一块区域 ...

  5. [C++学习历程]基础部分 C++中的指针数组和结构

    作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/19938177 一.指针 对学习C++来说,指针是一项重要内容,以前,教 ...

  6. C语言中的指针数组和数组指针

    代码: #include <iostream> using namespace std; int main(){ ]; ]; cout<<sizeof(a)<<en ...

  7. C语言的函数指针数组(好绕啊~看完这篇估计就通关了)

    转自https://www.cnblogs.com/chr-wonder/p/5168858.html int *(*p(int))[3] 今天有人问这个是啥?我一看直接就懵逼了…… 下面做一些简单的 ...

  8. C语言深度剖析-----指针数组和数组指针的分析

    指针数组和数组指针的分析 数组类型 定义数组类型 数组指针 这个不可能为数组指针,指向数组首元素 例 指针数组 例    main函数的参数 例 小结

  9. 嵌入式-C语言基础:指针数组(和数组指针区分开来)

    指针数组:一个数组,若其元素均为指针类型的数据,称为指针数组,指针数组存放的是指针类型的数据,也就是指针数组的每个元素都存放一个地址.下面定义一个指针数组: int * p[4];//[]的优先级是比 ...

  10. c语言指针数组和结构体的指针

    指向数组的指针,先初始化一个数组,使用传统方式遍历 void main() { ] = { ,,,, }; ; i < ; i++) { printf("%d,%x\n", ...

随机推荐

  1. 解决痛苦的方法/cy

    这篇文章 源于我所有痛苦的回忆. 由于痛苦太多了 体会完了 所以 觉得这些都不算是什么大问题了 所以 这里 是解决痛苦的方法. 真的很痛苦的话 可以这样 对着全班人喊你们 都没我强 因为 你们都没有我 ...

  2. yum自建离线仓库

    1.步骤 centOS的安装包,完整版最好--everyhing版本 解压缩 将文件夹内Packages文件导入系统 执行命令如下: 1. mv ./Packages/ /mnt/ 2. create ...

  3. Dropzone.js文件拖拽上传提示Dropzone already attached 解决

    最近收到客户的反馈,在操作上传文件有时会出现没有任何.大部分时间是正常. 重现问题后,f12打开后台控制台发现如下提示: Uncaught Error: Dropzone already attach ...

  4. 微信公众号如何将PDF上传到公众号?

    微信公众号如何将PDF上? 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...

  5. PHP基础之查找

    前言 之前的文章介绍了PHP的运算符.流程控制.函数.排序等.有兴趣可以去看看. PHP入门之类型与运算符 PHP入门之流程控制 PHP入门之函数 PHP入门之数组 PHP基础之排序 下面简单介绍一下 ...

  6. 网易云音乐ncm格式分析以及ncm与mp3格式转换

    目录 NCM格式分析 音频知识简介 两种可能 GitHub项目 格式分析 总体结构 密钥问题 代码分析 main函数 导入模块 dump函数 参考资料 代码完整版 转换工具 ncmdump ncmdu ...

  7. gym102586 部分题解

    目录 Evacuation Sum Modulo Count Modulo 2 Robots Construct Points Amidakuji Yosupo's Algorithm link 出于 ...

  8. 远程服务器的管理工具SSH

    1.SSH是什么? SSH:Secure Shell 安全外壳协议 建立在应用层基础上的安全协议 可靠,专为远程登录会话和其他网络服务提供安全性的协议 有效防止远程管理过程中的信息泄露问题 SSH客户 ...

  9. DB2 分组查询语句ROW_NUMBER() OVER() (转载)

    说起 DB2 在线分析处理,可以用很好很强大来形容.这项功能特别适用于各种统计查询,这些查询用通常的SQL很难实现,或者根本就无发实现.首先,我们从一个简单的例子开始,来一步一步揭开它神秘的面纱,请看 ...

  10. mapper.xml文件中传入list参数报错 ‘ ’附近有语法错误

    mapper.xml文件中传入list参数,使用foreach循环遍历值,但是在遍历的过程中出错了,具体代码如下所示 mapper.xml <select id="selectByCo ...