第二章 Go语言数据类型
一、整数类型
按照长度分为: int8 、int16 、int32 、int64
对应的无符号整型: uint8、uint16、uint32、uint64
获取对象的长度用len()
进制
十进制:
var a int = 10
fmt.Printf(“%d \n”,a) //10
fmt.Printf(“%b \n”,a) //1010 占位符%b表示二进制
八进制:
var b int = 077
fmt,Printf(“%o \n”,c) //ff
十六进制:
var c int = oxff
fmt.Printf(“%x \n”,c) //ff
fmt.Printf(“%X \n”,c) //FF
内存地址:
fmt.Printf(“%p \n”,&a) //0x00004c080 占位符%p表示十六进制的内存地址
注:不同int类型之间不能转换相加减,需要转换成相同类型
interface可以转换任意类型
func test() {
var a interface{} //{}表示空的interface
var b int = 100
var c float32 = 1.2
var d string = "hello"
a = b
fmt.Println("a=", a) //100
a = c
fmt.Println("a=", a) //1.2
a = d
fmt.Println("a=", a) //hello
}
二、浮点型
类型:float32和float64 不定义默认是0 浮点数不够精确,可以把浮点数先*100或*1000编程整数进行运算 占位符输出%f
三、布尔类型
类型:True和Flase 默认Flase go语言不能将整型强制转换成布尔型 布尔型无法参与数值运算,也无法与其他类型转换 用%t表示格式化
四、String类型
定义:以原生数据类型出现内部实现使用utf-8
表示字符串:
“ ” //双引号输出会出现转义符的意义
·· //反引号会忽视转义符的意义
字符串常用转义符:
\r:回车符(返回行首) \n:换行符(直接跳到下一行的同列位置) \t:制表符 \‘:单引号 \“:双引号 \:反斜杠
字符串常用方法
+或fmt.Sprintf //拼接字符串
(1)
c = c+c
fmt.Printf("c = %s\n",c)
(2)
c = fmt.Sprintf("%s%s",c,c)
fmt.Printf("c=%s\n",c)
strings.Split //分割
import "strings"
func test(){
ip := "10.10.10.1;192.168.1.1"
ipArray := strings.Split(ip,";")
fmt.Printf("first ip :%s\n",ipArray[0])
fmt.Printf("second ip :%s\n",ipArray[1])
}
strings.contains //判断是否包含
import "strings"
func test(){
ip := "10.10.10.1;192.168.1.1"
result := strings.Contains(ip,"10.10.10.1")
fmt.Println(result) //返回布尔值
}
strings.HasPrefix/HasSuffix //判断前缀和后缀
import "strings"
func test(){
str := "https://www.baidu.com"
if strings.HasPrefix(str,"http"){
fmt.Println("str is http url")
}else{
fmt.Println("str is not http url")
}
var last bool
last = strings.HasSuffix(str,"com")
fmt.Printf(last) //返回bool
}
strings.Index()/LastIndex() //子串出现的位置
import "strings"
func test(){
str := "https://www.baidu.com"
index := strings.Index(str,"baidu") //baidu第一次出现的位置
fmt.Printf("str is index:%d\n",index)
index = strings.LastIndex(str,"baidu") //baidu最后一次出现的位置
fmt.Printf("baidu last index:%d\n",index)
}
strings.Join(a[]string,sep string) //join操作,把一个数组每一个元素根据分隔符为基准重新组成字符串
func test(){
var strArr []string = []string{"10.10.10.1","11.11.11.2","12.12.12.3"}
resultStr = strings.Join(strArr,";")
fmt.Printf("result=%s\n"mresultStr) //输出result=10.10.10.1;11.11.11.2;12.12.12.3
}
五、字符类型
定义:组成字符串的元素叫做字符,字符用’ ‘表示,分别有uint8(byte)类型,代表一个ASCII码的字符;rune类型,代表一个UTF-8字符
package main
import "fmt"
func main(){
s1 := "Golang"
c1 := 'G'
fmt.Println(s1,c1) //Golang 71 字符的编码
s2 := "中国"
c2 := '中' //汉字表示3位
fmt.Println(s2,c2) //中国 20013
s3 := "Go语言"
fmt.Println(len(s3)) //11 一个字符1字节,中文3字节
for i := 0;i<len(s3);i++{ //bytes中文乱码
fmt.Printf("%c\n",s3[i]) //%c打印字符
}
for k,v := range s3{ //可打印中文字符
fmt.Printf("%d,%c\n",v) //k表示字节的索引数
}
}
强制转换字符串和utf-8
func main(){
s1 := "big"
bytes1 := []byte(s1) //将字符串强制转换成字节数组类型
fmt.Println(bytes1) //[98 105 103]分别对应了各自的字符
bytes1[0] = 'p'
fmt.Println(string(bytes1)) //[112 105 103]
s1 = string(bytes1) //将字节数组强制转换成字符串类型
fmt.Println(s1)
s2 := "大白菜"
runes2 := []rune(s2)
runes2[0] ='小'
fmt.Println(string(runes2),len(runes2))
}
//只有强制类型转换,不能重新赋值
字符串反转操作
//英文
func main(){
s1 := "hello"
byteArray := []byte(s1) //[h e l l o]
//方法1
s2 := ""
for i :=len(byteArray)-1;i>=0;i--{
s2 = s2 + string(byteArray[i]) //byteArray[i] --> o l l e h
}
fmt.Println(s2)
//方法2
for i := 0;i<len(byteArray)/2;i++{
byteArray[i],byteArray(len(byteArray)-1-i) = byteArray(length-1-i),byteArray[i]
}
fmt.Println(string(byteArray))
}
//中文
func main(){
str := "中文"
r []rune := []rune(str)
for i := 0;i<len(r)/2;i++{
tmp := r[len(str)-i-1]
r[len(str)-i-1] = r[i]
r[i] = tmp
}
fmt.Println(string(r[i]))
}
六、指针
变量和内存地址:每个变量都有内存地址,通过变量来操作对应大小的内存;普通变量存储的是对应类型的值,这些类型就叫做值类型
func main(){
var a int32
a = 100
fmt.Printf("the addr of a:%p",&a) //the addr of a:0x000062058
}
指针类型:指针类型的变量存储的是一个地址,所以又叫指针类型或引用类型;操作指针变量指向地址里的值
func test(){
var a int32
a = 156
fmt.Printf("the addr of b:%p,b:%v\n",&b,b)
if b == nil{
fmt.Println("这个指针变量为空")
}
b = &a //将a变量地址传到b中
fmt.Printf("the addr of b:%p,b:%v\n",&b,b) //b的内容为a的地址,但b的内存地址与a不同
}
func test2(){
var a int = 200
var b *int = &a
fmt.Printf("b指向的地址存储的值为:%d\n",*b) //打印b中存储的内存地址所存的数值
*b = 1000 //修改b存的内存地址所存得数值
fmt.Printf("b指向的地址存储的值为:%d\n",*b)
fmt.Printf("a=%d\n",a)
}
指针传参
func modify(a *int){
*a = 100
}
func testvariable(){
var b int = 10
p := &b
modify(p)
fmt.Printf("b:%d\n",b) //b:100
}
//在p定义一个指针变量,把p传入modify中a会拷贝一份b的内存地址在自己的值中,a就可以操作b的值
//数组
func modify(a *[3]int){
(*a)[0] = 100
}
func testvariable(){
var b [3]int = [3]int{1,2,3}
modify(&b)
fmt.Println(b) //[100,2,3]
}
make和new的区别:
make用来分配引用类型的内存,比如map,slice以及channel
new用来分配除引用类型的所有其他类型的内存,比如int和数组
func testvariable(){
var a *int = new(int)
*a = 100
fmt.Printf("*a=%d\n",*a) //整型可以直接操作
var b *[]int = new([]int)
fmt.Printf("*b = %v\n",*b)
(*b) = make([]int,5,10) //切片只有make后才能进行操作,否则报错
(*b)[0] = 100
(*b)[1] = 200
fmt.Printf("*b = %v\n",*b)
}
值拷贝和引用拷贝
//值拷贝
func modify(){
a = 100
}
func testvariable(){
var b int = 10
modify(b)
fmt.Printf(*b=%d\n",b)
} //b的值不变,调用modify函数是会把值拷贝过去一份,但是内存地址不一样
//引用拷贝
func testvariable(){
var a int = 10
var b *int = &a
var c *int = b
*c = 200
fmt.Printf("*c=%d *b=%d a=%d\n",*c,*b,a)
} //a的内存地址都拷贝到b和c中,所以一个操作都会修改
七、Array数组
定义:表示同一种数据类型的集合,数组长度从声明的时候就确定了,使用时可以修改数组成员,但是数组大小不可变化
var a [3] int //定义一个数组,数组下标从0开始,因此长度为n的数组下标范围:[0,n-1];
整数数组中的元素默认初始化为0,字符串数组中的元素默认初始化为””
数组初始化:不同数组的长度和类型不同,则不能直接赋值
func test(){
a := [3]int{1,2,3}
b := [5]int
b = a //不成立
}
func test2(){
var a [3] int //定义一个长度为3的int型数组
a[0] = 10 //分别给数组中的位置传值
a[1] = 20
a[2] = 30
//方法2
var a [3]int = [3]int{10,20,30}
//方法3
a := [3]int{10,20,30}
//方法4
a := [...]int{10,20,30} //...表示任意长度,由传入的参数决定
//方法5
a := [3]int{10} //10,0,0
//方法6
a := [3]int{2:10} //索引为2的元素初始值换成10
数组遍历
func testArray(){
a := [5]int{3:100,4:300}
for i:=0;i<len(a);i++{
fmt.Printf("a[%d]=%d\n",i,a[i]) //打印索引位和该索引位的数值
}
}
func testArray(){
a := [3]int{1,2,3}
for index,value := range a{ //range会返回两个数,第一个为range的下标,第二个是值
fmt.Printf("a[%d]=%d\n",index,value) //当不需要index时可以用_代替
}
}
二维数组
func testArray(){
var a [3][2]int
a[0][0] = 10
a[0][1] = 20
a[1][0] = 30
a[1][1] = 40
a[2][0] = 50
a[2][1] = 60
fmt.Println(a) //[[10 20] [30 40] [50 60]]
for i :=0;i<3;i++{
for j:=;j<2;j++{
fmt.Printf("%d",a[i][j] //10 20 30 40 50 60
}
for i,val1 := range a{
for k,val2 :=range bal1{
fmt.Printf("(%d,%d)=%d",i,j,val2) //(0,0)=10 (0,1)=20.......
}
}
}
数组拷贝和传参
//拷贝
func testArray(){
var a [3]int
a[0] = 10
a[2] = 20
a[3] = 30
b := a //b拷贝了数组a总所有的元素
b[0] = 1000
fmt.Println(a,b) //[10,20,30] [1000,20,30] //拷贝的值相同,内存地址不同
}
//传参
func testArray(){
a := [3]int{10,20,30}
modify(a) //当一个数组作为参数传递时,会将值拷贝一份过去
fmt.Println(a) //[10 20 30]
}
func modify(b [3]int){
b[0] = 1000 //修改此处的值不影响原数据
return
}
八、Slic切片
定义:是基于数组类型作的一层封装,可以自动扩容 var a []int //定义一个int类型的切片
//初始化切片
func test(){
a := [5]int{1,2,3,4,5}
var b []int = a[1:4]
fmt.Println(b) //[2 3 4]
}
func test2(){
a := []int{1,2,3}
fmt.Println(a)
}
//切片的基本操作
functest(){
a := []int{1,2,3,4,5,6,7,8}
var b []int = a[2:6] //下标从2到6的元素,不包括6
fmt.Println(b) //[3 4 5 6]
var c []int = a[3:] //从下标为3的元素到最后元素,包括3
fmt.Println(c) //[4 5 6 7 8]
var d []int = a[:5] //下标为0的元素到下标5的元素,包括0但不包括5
fmt.Println(d) //[1 2 3 4 5]
var e []int = a[:] //包括这个数组的所有元素
fmt.Println(e) //[1 2 3 4 5 6 7 8]
//修改切片:切片的修改是对应数组的,改的是数组的内存地址
func test(){
{
a := [..]int{1,2,3,4,5,6,7,8}
b := a[2:5]
b[0] = b[0] + 10
b[1] = b[1] + 10
b[2] = b[2] + 10
fmt,Println(a) //[1,2,13,14,15,6,7,8}
darr := [...]int{1,2,3,4,5,6}
dslice := darrr[2:5]
fmt.Println(“array before”,darr) //{1,2,3,4,5,6}
for i,v:= range dslice{
dslice[i]++
fmt.Println(i,v) //获取到下标i和值v,修改数据要用切片对应的下标进行修改
}
fmt.Println("arraty after",darr) //[1,2,4,5,6,6}
}
//make创建切片
func test(){
a := make([]int,5,10) //5表示长度,10 表示容量,容量从0开始
a[0] = 10
a[1] = 20
a = append(a,30) //长度表示显示长度,容量表示内存容量,切片可以通过append添加,当容量不足时,append还可以对属于组进行扩容,当append扩容的时候,底层为新建一个双倍容量的内存空间,把之前的数组内容拷贝进去
fmt.Println(a) //[10,20,0,0,0,30]
}
func test2(){
a := make([]intt,0,10}
fmt.Println(b,len(b),cap(b))
b = append(b,100)
fmt.Println(b,len(b),cap(b)) //无长度,添加到数组的第一个位置
}
//切片再切片
func test(){
a := [...]string{"a","b","c","d","e","f"}
b := a[1:3[
fmt.Println(b,len(b),cap(b)) //[b,c]长度2,容量5 [b c] 2 5
b = b[:cap(b)]
fmt.Println(b,len(b),cap(b)) //这样切片会让长度=容量==5 [b c d e f] 5 5
}
//空切片和扩展策略
func testnil() {
var a []int
fmt.Println(a, len(a), cap(a))
if a == nil {
fmt.Println("a is nil")
}
a = append(a, 100)
fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100],0xc0000100a8,len:1,cap1 %p表示内存地址
a = append(a, 200)
fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200],0xc000010100,len:2,cap2
a = append(a, 300)
fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300],0xc00000a400,len:3,cap4
a = append(a, 400)
fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300 400],0xc00000a400,len:4,cap4
a = append(a, 500)
fmt.Printf("%d,%p,len:%d,cap%d\n", a, a, len(a), cap(a)) //[100 200 300 400 500],0xc00000e280,len:5,cap8
}
//切片传参
func test(){
a := []int{1,2,3}
b := []int{4,5,6}
a = append(a,23,34,45)
fmt.Println(a) //[1,2,3,,23,34,45]
a = append(a,b...)
fmt.Println(a) //[1,2,3,23,34,45,4,5,6]
}
func test2(){
var a []int = []int{1,2,3}
var b []iont = []int{4,5,6}
vvopy(a,b)
fmt.Println(a) //[4,5,6]
fmt.Println(b) //[4,5,6]
var c []int = []int{1,2}
var d []int = []int{4,5,6}
copy(c,d)
fmt.Println(c) //[4,5]
fmt.Println(d) //[4,5,6]
}
九、Map哈希表
定义:map类型是一个key-value的数据结构
声明:var a map[key的类型]value类型。如:var a map[string]int var b map[int]string var c map[float32]string
//初始化 map必须初始化才能使用
func test(){
var a map[string]int
fmt.Pringf("a:%v\n",a)
if a == nil{ //根据是否为空判断有没有初始化
a = make(map[string]intm,16) //初始化map并定义容量16
fmt.Printf("a=%v\n",a)
a["stu01"]=1000
fmt.Printf("a=%v\n",a) //a = map【sttu01:1000]
}
}
func test2(){
a := map[string]int
"steve":12000, //逗号要加
"jamie":15000
}
a["mike"] = 9000
fmt.Println("a map contents:",a)
}
//map插入操作
func test(){
a := make(map[string]int)
a["steve"] = 12000
a["jamie"] = 15000
a["mike"] = 9000
fmt.Println("a map contents:",a) //a map contents:map[jamie:15000 mike:9000 steve:12000]
}
//通过key访问map中的元素
func test(){
a := map[string]int{
"steve":12000,
"jamie":15000
}
a["mike"] = 9000
b := "jamie"
fmt.Println("Salary of",b,"is","a[b]) //Salary of jamie is 15000
}
//判断map指定的key是否cunzai
func test() {
a := map[string]int{
"stu01": 1000,
"stu02": 2000,
}
b := "joe"
value,ok := a[b] //valuesahib值,ok是布尔类型
if ok == false {
fmt.Printf("key %s is not exisst\n",b)
} else{
fmt.Printf("key %s is %d\n",b,value)
}
}
//遍历map
func test() {
a := map[string]int{
"stu01": 1000,
"stu02": 2000,
}
fmt.Println("all items of a map")
for key,value := range a{
fmt.Printfd("["[%s]=%d\n",key,value)
}
}
//map删除元素
func test() {
a := map[string]int{
"stu01": 1000,
"stu02": 2000,
}
fmt.Println("map before deletion",a)
delete(a,"steve")
fmt.Println("map after deletion",a)
}
//map的长度
func testmap() {
a := map[string]int{
"stu01": 1000,
"stu02": 2000,
}
fmt.Println("length is", len(a))
}
//map是引用类型
func testmap() {
a := map[string]int{
"stu01": 1000,
"stu02": 2000,
}
fmtPrintln("origin map",a)
b := a //b引用了a的内存地址
b["steve"] = 1800 //b变了,a也变了
fmt.Println("a map changed",a)
}
//map排序
func test() {
var a map[string]int = make(map[string]int, 10)
for i := 0; i < 10; i++ {
key := fmt.Sprintf("key%d", i)
a[key] = i
}
var keys []string = make([]string, 0, 10)
for key, value := range a {
fmt.Printf("key:%s = %d\n", key, value) //默认是无序的
keys = append(keys, key) //将map添加到数组中
}
sort.Strings(keys) //将数组排序
for _, value := range keys {
fmt.Printf("key:%s val:%d\n", value, a[value])
}
}
//map类型的切片
func test() {
var mapSlice []map[string]int //定义一个切片中是map
mapSlice = make([]map[string]int, 3, 10) //初始化切片
fmt.Println("before map init")
for index, value := range mapSlice { //遍历切片中的map
fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println()
mapSlice[0] = make(map[string]int, 10) //初始化map
mapSlice[0]["a"] = 1000
mapSlice[0]["b"] = 2000
fmt.Println("after map init")
for index, value := range mapSlice { //遍历切片中的map
fmt.Printf("index:%d value:%v\n", index, value)
}
}
func test() {
var s map[string][]int //定义一个map中是切片
s = make(map[string][]int, 16) //初始化map
key := "stu01" //定义一个键
value, ok := s[key] //判断该键的切片是否存在
if !ok { //如果不存在则初始化该键对应的切片
s[key] = make([]int, 0, 16)
}
value = append(value, 100)
value = append(value, 200)
s[key] = value //将value赋值s[key]
fmt.Printf("map:%v\n", s)
}
十、Struct结构体
定义:go中面向对象时通过struct来实现的
//struct初始化方法
type User struct {
Username string
Sex string
Age int
AvatarUrl string
}
func test(){
//方法一
var user User
user.Age = 18
user.Username = "user01"
user.Sex = "男"
user.AvatarUrl = "www.baidu.com"
//方法二
var user User = User{
Username : "user01"
Age : 18
Sex : "男"
AvatarUrl : www.baidu.com
}
//方法三
user := User{
Username : "user01"
Age : 18
Sex : "男"
AvatarUrl : www.baidu.com
}
fmt.Printf("user.name=%s age=%d sex=%s avatar=%s\n", user.Username, user.Age, user.Sex, user.AvatarUrl)
}
//结构体类型的指针
var user *User = &User{}
fmt.Printf("%p %#v\n",user)
var user *User = &User{
Username : "user01"
Age : 18
Sex : "男"
AvatarUrl : www.baidu.com
}
var user User = new(User)
Username = "user01"
Age = 18
Sex = "男"
AvatarUrl = www.baidu.com
func test() {
var user *User
fmt.Printf("user=%v\n", user) //user=<nil>
var user01 *User = &User{}
user01.Age = 18
user01.Username = "user01"
fmt.Printf("user01=%#v\n", user01) //user01=&main.User{Username:"user01", Sex:"", Age:18, AvatarUrl:""}
}
struct的内存布局以及构造函数
//结构体的内存布局:占用一段连续的内存空间
type Test struct{
A int32
B int32
C int32
D int32
}
func test(){
var t Test
fmt.Printf("a addr:%p\n", &t.A) a addr:0xc000062070
fmt.Printf("b addr:%p\n", &t.B) b addr:0xc000062074
fmt.Printf("c addr:%p\n", &t.C) c addr:0xc000062078
fmt.Printf("d addr:%p\n", &t.D) d addr:0xc00006207c
} //每块占用4字节,在内存中连续
//无构造函数,需要自己定义
import "导入user包"
func main(){
var u user.User
u.Age = 18
fmt,Printf("user.%#v\n",u)
}
package user
type User struct{
Username string
Sex string
Age int
AvatarUrl string
}
匿名字段和struct嵌套
//匿名字段:没有定义名字的字段
type User struct{
Username string
Sex string
Age int
AvatarUrl string
int //匿名字段
string //匿名字段
}
func main(){
var u User
u.Username = "user01"
u.Sex = "man"
u.int = 100
u.string = "hello"
fmt.Printf("user=%#v\n“,u”)
}
//匿名字段默认采用类型名作为字段名
type Address struct{
Province string
City string
}
type User struct{
Username string
Sex string
&Address
}
func test()[
var user User
user.Username = "user"
user.Sex = "man"
user.Address = &Address{ //第一种方式
Province : "北京",
City : "北京",
}
user.Province = "北京" //第二种方式
user.City = "北京"
}
//匿名字段冲突
type Address struct{
Province string
City string
}
type User struct{
City string
Username string
Sex string
*Address
}
func test()[
var user User
user.Username = "user"
user.Sex = "man"
user.City = "北京"
fmt.Printf("user=%#v\n",user)
user.Address = new(Address) //指针必须初始化
fmt.Printf("user=%#v\n",user)
user.Address.City = "北京"
fdmt.Printf("user=%#v city of address:%s\n",user,user.Address.City)
结构体链表
单链表定义:每个节点包含下一个节点的地址,这样把所有的节点串起来叫做单链表,第一个节点叫做链表头
双链表定义:如果两个指针分别指向前一个节点和后一个节点,就是双链表
//单链表
type Studfent struct()[
Name string
Next *Student
}
//双链表
type Student struct{
Name string
Next *Student
Preve *Student
}
结构体二叉树
定义:如果每个节点有两个指针分别用来是想左子树和柚子树,这样的结构就是二叉树
type Student struct{
Name string
Age int
Score float64
Left *Student
Right *Student
}
func trans(root *Student){
if root == nil{
return
}
fmt.Println(root) //前序遍历
trans(root.Left)
trans(root.Right)
}
func main(){
var root *Student = new(Student)
root.Name = "stu01"
root.Age = 19
root.Score = 100
var left1 *Student = new(Student)
left1.Name = "stu02"
left1.Age = 19
ledt1.Score = 100
root.Left = left1
var rigtht1 *Student = new(Student)
right1.Name = "stu04"
right1.Age = 19
right1.Score = 100
root.Right = right1
var left2 *Student = new(Student)
left2.Name = "stu02"
left.Age = 19
left.Score = 100
left2.Score = 100
left1.left = left2
trans(root)
}
//&{stu01 19 100 0xc000078330 0xc000078360}
//&{stu02 19 100 0xc000078390 <nil>}
//&{stu03 19 100 <nil> <nil>}
//&{stu04 19 100 <nil> <nil>}
func trans(root *Student){
if root == nil{
return
}
trans(root.left)
fmt.Println(root) //中序遍历
trans(root.right)
}
//&{stu03 19 100 <nil> <nil>}
//&{stu02 19 100 0xc000078390 <nil>}
//&{stu01 19 100 0xc000078330 0xc000078360}
//&{stu04 19 100 <nil> <nil>}
func trans(root *Student){
if root == nil{
return
}
trans(root.left)
trans(root.right)
fmt.Println(root) //后序遍历
}
//&{stu03 19 100 <nil> <nil>}
//&{stu02 19 100 0xc000078390 <nil>}
//&{stu04 19 100 <nil> <nil>}
//&{stu01 19 100 0xc000078330 0xc000078360}
工厂模式
定义:golang中struct没有构造函数,可以用工厂模式来解决这个问题
//简单工厂模式
package easyfactory
import "errors"
type operation struct{
}
type cal interface(
cal(int,int) (float64,error)
}
type operationAdd struct{
operation
}
func (o *operationAdd) cal(num1,num2 int) (float64,error) {
return float64(num1+num2),nil
}
type operationMinus struct {
operation
}
func (o *operationMinus) cal(num1,num2 int) (float64,error) {
return floaf64(num1-num2),nil
}
type operationMulti struct {
operation
}
func (o *operationMulti) cal(num1,num2 int) (float,errror) {
return float64(num1 * num2),nil
}
type operationDiv struct{
operation
}
func (o *operationDiv) cal(num1,num2 int) (float64,error) {
if num2 == 0{
return 0,errors.New("除法运算中除数不能为0")
}
return float64(num1/num2),nil
}
type operationFactory struct{}
func (o *operationFactory) createOperation(op string) cal {
switch op{
case "+":
return new(operationAdd)
case "-":
return new(operationMinus)
case "*":
return new(operationMulti)
case "/":
return new(operationDiv)
}
return nil
}
struct和tag应用
定义:tag是结构体的原信息,可以运行的时候通过反射的机制读取出来,字段类型后面,以反引号的key:value结构的字符串,多了tag以逗号隔开
type User struct{
Username string `json:"username"`
Sex string `json:"sex"`
Score float32
}
func main(){
user := & User {
Username:"user01",
Sex:"男",
Score: 84,
}
data,_ := json.Marshal(user) //第二个接收的数据是错误,为nil
fmt.Printf("json str:%s\n",string(data))
}
方法
定义:go的方法是在函数面前加上一个接收者,这样编译器就知道这个方法属于哪个类型
type A struct{
}
func (a A) Test(s string){ //通过a来访问A的实例中的成员变量,也就是struct的字段
}
func main(){
var t A
t.Test() //调用方法
}
type People struct{
Name string
Country string
}
func (p People) Print() {
fmt.Printf("name=%s country=%s\n",p.Name,p.Country)
}
func (p People) Set(name,country string) {
p.Name = name
p.Country = country
}
func test() {
var p1 People = People{
Name : "pe01",
Country : "china",
}
p1.Print() //pe01 china
p1.Set("pe02","Ch")
p1.Print() //pe01 china Set修改的数据通过值拷贝传出,原地址数据不变
}
//可以为当前包内定义的任何类型增加方法
type Integer int //创建Integer为int的别名
func (i Integer) Print() {
fmt.Println(i)
}
func test() {
var a Integer //设定一个变量为Integer类型
a = 1000
a.Print() //调用int自定义的Print方法
var b int = 200
a = Integer(b)
a.Print()
}
值类型和指针类型
type People struct {
Name string
Country string
}
func (p People) Print() {
fmt.Printf("name=%s country=%s\n",p.Name,p.Country)
}
func (p *People Set(name,country string) {
p.Name = name
p.Country = country
}
func test() {
var p1 People = People{
Name:"pe01",
Country:"china",
}
p1.Print()
(&p1).Set2("pe02","Ch") //指针地址内容改变,所以数据改变,也可以写成p1.Set("pe02","Ch")
p1.Print()
}
匿名字段和继承
type Animal struct{
Name string
Sex string
)
func (a *Animal) Talk() {
fmt.Printf("i,talk,i'm %s\n",a.Name)
}
type Dog struct{
Feet string
*Animal //或者Animal 通过组合来实现继承
}
func (d *Dog)Eat() {
fmt.Println("dog is eat")
}
func test() {
var d *Dog &Dog{
Feet:"four feet",
Animal:&Animal{
Name:"dog",
Sex:"xiong"
},
}
d.Eat()
d.Talk()
}
多重继承与冲突解决
type Dog struct{
Feet string
*Animal1
*Animal2
}
type Animal1 struct {
Name string
Sex string
}
func (a *Animal1) Talk(){
fmt.Printf("i,talk,i'm %s\n",a.Name)
}
type Animal2 struct {
Name string
Sex string
}
func (p *Animal2) Talk(){
fmt.Println("Animal2")
}
func test() {
var d *Dog = &Dog{
Feet:"four feet",
Animal1:&Animal1{
Name:"dog",
Sex:"xiong",
},
}
d.Animal1.Talk()
d.Animal2.Talk()
}
结构体和Json序列化
//序列化 struct转json
import "encoding/json"
type Student struct{
Id int
Name string
Sex string
}
type Class struct{
Name string
Count int
Student []*Student
}
func test(){
c := &Class{
Name:"101",
Count:0,
}
for i:= 0,i<10;i++{
stu := &Student{
Name :fmt.Sprintf("stu%d",i),
Sex :"man",
Id:i,
}
c.Student = append(c.Student,stu)
}
data,err := json.Marshal(c)
if err != nil{
fmt.Println("json marashal failed")
return
}
fmt.Printf("json:%s\n",string(data))
}
//反序列化 json装struct
type Student struct{
Id int
Name string
Sex string
}
type Class struct{
Name string
Count int
Student []*Student
}
var rawJson = `{"Name":"101","Count":0,"Student":[
{"Id":0,"Name":"stu0","Sex":"man"},{"Id":1,"Name":"stu1","Sex":"man"},
{"Id":2,"Name":"stu2","Sex":"man"},{"Id":3,"Name":"stu3","Sex":"man"},
{"Id":4,"Name":"stu4","Sex":"man"},{"Id":5,"Name":"stu5","Sex":"man"},
]
}`rint
var c1 *Class = &Class{}
err := json.Unmarshal([]byte(rawJson),c1)
if err != nil{
fmt.Println("unmarshal failed")
return
}
fmt.Printf("c1:%#v\n",c1)
/*c1:&main.Class{
Name:"101", Count:0, Student:[]*main.Student{
(*main.Student)(0xc00007a510), (*main.Student)(0xc00007a540),
(*main.Student)(0xc00007a570), (*main.Student)(0xc00007a5a0),
(*main.Student)(0xc00007a600), (*main.Student)(0xc00007a630),
}*/
for _,v := range c1.Student{
fmt.Printf("stu:%#v\n",v)
/*stu:&main.Student{Id:0, Name:"stu0", Sex:"man"}
stu:&main.Student{Id:1, Name:"stu1", Sex:"man"}
stu:&main.Student{Id:2, Name:"stu2", Sex:"man"}
stu:&main.Student{Id:3, Name:"stu3", Sex:"man"}
stu:&main.Student{Id:4, Name:"stu4", Sex:"man"}
stu:&main.Student{Id:5, Name:"stu5", Sex:"man"}*/
}
}
十一、时间和日期
使用time包中的time.Time类型用来表示时间
获取当前时间:
now := time.Now() 获取当前时间
now := time.Now().Day()
now := time.Now().Minute()
now := time.Now().Month()
now := time.Now().Year()
格式化:
func main(){
now := time.Now()
fmt.Printf("current time:$v\n",now)
tear := now.Year()
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
send := now.Second()
fmt.Printf("%02d-%02d-%02d-%02d-%02d-%02d", year, month, day, hour, minute, send)
}
定时器
func main(){
ticker := time.Tick(5*time.Second) //每5s执行一次其中的函数
for i := range ticker{
fmt.Printf("%v\n",i)
函数()
}
}
格式化
func main(){
now := time.Now()
fmt.Println(now.Format("02/1/2006 15:04"))
fmt.Println(now.Format("2006/1/02 15:04"))
fmt.Println(now.Format("2006/1/02"))
}
//格式可以换,时间必须为2006 1 02 15:04
计算程序运行时间
func main(){
start := time.Now().UnixNano()
for i := 0;i<10;i++{
time.Sleep(time.Millisecond)
}
end := time.Now().UnixNano()
cost := (end - start)/1000000 //微秒化成秒
fmt.Printf("%vn",cost)
}
十二、if-else
//分支结构
func main(){
age := 19
if age >18{
fmt.Println("澳门赌场")
}else if age <18{
fmt.Println("Waring...")
}else{
fmt.Println("成年了")
}
}
//特殊写法
func main(){
age := 18
if age ==18{
fmt.Println("成年”)
}
if age2 := 28;age2 >18{
fmt.Println("成年了")
}
fmt.Println(age2) //报错,在判断条件中定义变量无法在判断条件外打印
}
十三、switch-case
定义:用于if条件多时
//每个switch只能有一个default分支
func test(){
t:=3
switch t{
case 1 : //如果条件t是1则执行
fmt.Println("大拇指")
case 2 : //如果条件t是2则执行
fmt.Println("食指")
default: //否则输出
fmt.Println("无效的输入")
}
//一个分支可以有多个值,之间用逗号分隔
func test2(){
switch t := 7;t{
case 1,3,5,7,9:
fmt.Println("奇数")
case 2,4,6,8:
fmt.Println("偶数")
default:
fmt.Println(n)
}
}
//分支可以使用表达式,此时switch后不需要再跟判断变量
func test3(){
age :=30
switch {
case age <25:
fmt.Println("好好学习")
case age >25:
fmt.Println("好好工作")
case age >60:
fmt.Println("活着真好")
}
}
//fallthrough语法可以执行满足条件的case的下一个case,是为了兼容c语言中的case设计的
func test4(){
s := "a"
switch{
case s == "a" : //成立
fmt.Println("a")
fallthrough //无条件的执行下一个case语句
case s =="b":
fmt.Println("b")
case s=="c":
fmt.Println("c")
default:
fmt.Println("...")
}
}
十四、for
//for循环
for 初始语句;条件表达式;结束语句{
循环体语句
}
func test(){
a := 3
for i := 0;i<a;i++{ //定义i=0,如果i<a,则成立执行循环,循环结束后i++
fmt.Println(i)
}
}
//无线循环
for {
循环体语句
} //可以通过break,goto,return,panic强制退出
for range:键值循环
数组:返回索引和值 切片:返回索引和值 字符串:返回索引和值 map:返回键和值 通道(channel):只返回通道内的值
十五、goto/continue/break
break:退出当前循环,后加标签直接退出到标签处
continue:返回执行下一次循环,后加标签循环下一次的标签处
goto:通过标签进行代码间的无条件跳转,可以快速跳出循环,避免重复退出
//goto
func test(){
for i := 0;i<5;i++{
for j:=0;j<3;j++{
if i == 2 && j == 2{
goto yhc //直接跳转到yhc
}
}
}
fmt.Println("两层for循环结束")
yhc : //定义一个标签label
}
转载于//www.cnblogs.com/parallel-Y/p/11311603.html
还没有评论,来说两句吧...