slice
数组(固定长度)定义:
var nums [10] intnums := [5] int {1,2,3,4,5}- 遍历:
range返回下标和值 - 固定长度的数组作为参数传递时,要严格匹配数组类型,包括数组长度,而且是值传递,不能修改数组内的值
切片(动态数组):
myArray := []int{1,2,3,4}-
//遍历: for _ , value := range myArray{ fmt.Println("value=",value) } - 切片作为参数传递是引用传递,是可以改变值的。
定义切片的四种方式:
slice1 := []int{1,2,3}声明切片并初始化,长度为3-
var slice1 []int //声明切片但是没有分配空间 slice1 =make( []int, 3) // 给切片开辟空间,长度为3,默认值为0 slice1[0]=10 //有空间之后就可以赋值 -
var slice1 []int =make([]int,3)//声明切片并分配空间,初始化值为0 -
slice:=make([]int,3) //自动类型匹配
切片容量追加:
var numbers = make(int[] , 3, 5) //切片长度为3,容量为5
numbers=append(numbers,1) //追加元素,切片长度为4,容量为5
numbers=append(numbers,2) //追加元素,切片长度为5,容量为5
//slice [0,0,0,1,2]
//向容量已满的切片中追加元素:
numbers=append(numbers,3) //追加元素,切片长度为6,容量为10,扩容两倍
////slice [0,0,0,1,2,3]
var numbers = make(int[] , 3) //切片长度为3,没有规定容量,就默认是3
numbers=append(numbers,1) //追加元素,切片长度为4,容量为6,还是扩容两倍
len():切片长度
cap():切片容量
切片截取:
s:=[]int{1,2,3} //没有设置容量,默认容量为长度
s1:=s[0,2] //[1,2] 左闭右开
//s和s1指向的是同一块空间,所以二者搜可以修改数组值
//copy 又开辟另一块空间
s2:=make([]int,3) //[0,0,0]
copy(s2,s) //[1,2,3]
map
三种声明方式:
var myMap1 map[string]string //声明一个map,括号内表示key的类型,括号外表示value的类型,此时map为nil
make(map[string]string,10)//为map开辟10个键值对空间
//map有容量之后就可以赋值
myMap1["one"]="java"
myMap1["two"]="c++"
myMap1["three"]="go"
//满了之后也会动态扩存
myMap2 :=make(map[int]string)
myMap1[1]="java"
myMap1[2]="c++"
myMap1[3]="go"
myMap3 :=map[int]string{
1:"java",
2:"c++",
3:"python",
}
使用:
city := make(map[string]string)
//增加
city["china"]="beijing"
city["japan"]="tokyo"
city["usa"]="newyork"
//遍历
for key,value :=range city{
fmt.Println("key=",key)
fmt.Println("value=",value)
}
//删除
delete(city,"usa")
//修改
city["china"]="shanghai"
map作为方法形参传递时是引用传递,是可以修改原来的map的。
面向对象特征
struct:结构体,类似于Java中的类
type Book struct{
title string
auth string
}
var book1 Book
book1.title="golang"
book1.auth="zhang3"
封装:通过类名或属性名的首字母大小写来实现
type Hero struct{ //类名首字母大小,表明其他包也能访问该类,类似于public 这就是go的封装
Name string //属性名首字母大小,表示类的外部也能访问该属性
Id int
Level int
}
func (this *Hero) GetName() string{
return this.Name
}
func (this *Hero) SetName(newName string){
this.Name=newName
}
func (this *Hero) show(){
fmt.Println("Name=",this.Name)
fmt.Println("Id=",this.Id)
fmt.Println("Level=",this.Level)
}
func main(){
//创建对象
hero := Hero{Name:"zhang3",Id:100, Level : 1}
hero.show()
}
继承: 在子类的定义中写上父类的类名
type Human struct{
name string //属性名首字母小小,表示类的外部不能访问该属性
sex string
}
func (this *Human) Eat() {
fmt.Println("human eat")
}
func (this *Human) Walk() {
fmt.Println("human walk")
}
//子类
type SuperMan struct{
Human //表示superman继承了Human的方法
level int
}
//重新定义父类的方法
func (this *SuperMan) Eat() {
fmt.Println("superman eat")
}
//添加子类新的方法
func (this *SuperMan) Fly() {
fmt.Println("superman fly")
}
func main(){
//创建对象
h := Human{"zhang3","nan"}
s := SuperMan{Human{"zhang3","nan"},2}//子类对象
s.Walk() //调用父类的方法
s.Eat() //调用子类的方法
s.Fly() //调用子类的方法
}
多态:父类(接口)、子类(实现类,重写了接口的全部方法)、父类类型的变量(指针)指向(引用)子类的具体数据变量
type AnimalIF interface{
Sleep()
GetColor() string
GetType() string
}
type Cat struct{ //具体的类1
color string
}
//重写了接口的全部方法,就表示实现了这个接口
func (this *Cat) Sleep() {
fmt.Println("cat sleep")
}
func (this *Cat) GetColor() string {
return this.color
}
func (this *Cat) GetType() string {
return "Cat"
}
type Dog struct{ //具体的类2
color string
}
func (this *Dog) Sleep() {
fmt.Println("dog sleep")
}
func (this *Dog) GetColor() string {
return this.color
}
func (this *Dog) GetType() string {
return "Dog"
}
func main(){
var animal AnimalIF //声明一个接口,父类指针
animal=&Cat("green")
animal.Sleep() //调用实现类1的sleep()
animal=&Dog("white")
animal.Sleep //调用实现类2的sleep()
}
interface:通用万能类型
interface{} 空接口
func myFunc(arg interface{}){
fmt.Println(arg)
}
type Book struct{
auth string
}
func main(){
book := Book("Golang")
myFunc(book) //输出:{Golang}
myFunc(100) //输出:100
}
interface{}该如何区分底层引用的数据类型是什么?给interface{}提供断言的机制-
value,ok:=arg.(string) //ok为true,表明arg类型为string,此时value=string
反射
变量结构:
- 变量包括(type, value)两部分
- type 包括
static type和concrete type.static type是在编码阶段能看见的类型(如int、string),concrete type是runtime系统看见的类型 - 类型断言能否成功,取决于变量的
concrete type,而不是static type. 因此,一个reader变量如果它的concrete type也实现了write方法的话,它也可以被类型断言为writer.
var a string
a = "abc" //pair<statictype:string,value:"abc">
var allType interface{}
allType = a //传递:pair<type:string,value:"abc">
反射:可以获取对象的类型和值,通过对象获取类的属性名和类型,以及方法名
import {
"fmt"
"reflect"
}
func reflectNum(arg interface{}){
fmt.Println("type:",reflect.TypeOf(arg))
fmt.Println("value:",reflect.ValueOf(arg))
}
func main(){
var num float64=1.2345
reflectNum(num)
}
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int
Name string
Age int
}
func (u User) ReflectCallFunc() {
fmt.Println("Allen.Wu ReflectCallFunc")
}
func main() {
user := User{1, "Allen.Wu", 25}
DoFiledAndMethod(user)
}
// 通过接口来获取任意参数,然后一一揭晓
func DoFiledAndMethod(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("get Type is :", getType.Name())
getValue := reflect.ValueOf(input)
fmt.Println("get all Fields is:", getValue)
// 获取方法和属性 字段
// 1. 先获取interface的reflect.Type,然后通过NumField进行遍历
// 2. 再通过reflect.Type的Field获取其Field
// 3. 最后通过Field的Interface()得到对应的value
for i := 0; i < getType.NumField(); i++ {
field := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
}
// 获取方法
// 1. 先获取interface的reflect.Type,然后通过.NumMethod进行遍历
for i := 0; i < getType.NumMethod(); i++ {
m := getType.Method(i)
fmt.Printf("%s: %v\n", m.Name, m.Type)
}
}
运行结果:
get Type is : User
get all Fields is: {1 Allen.Wu 25}
Id: int = 1
Name: string = Allen.Wu
Age: int = 25
ReflectCallFunc: func(main.User)
结构体标签
type resume struct{
Name string 'info:"name" doc:"名字"'
Sex string 'info:"sex"'
}
func findTag(str interface{}){
t:=reflect.TypeOf(str).Elem();
for i:=0;i<t.NumFiled();i++ {
taginfo := t.Filed(i).Tag.Get("info")
tagdoc := t.Filed(i).Tag.Get("doc")
fmt.Println("info",tagstring)
}
}
func main(){
var re resume
findTag(&re)
}
结构体和json互相转换