Go 语言入门:基础语法和常用特性②|青训营

60 阅读5分钟

slice

数组(固定长度)定义:

  • var nums [10] int
  • nums := [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 typeconcrete type. static type是在编码阶段能看见的类型(如int、string),concrete typeruntime系统看见的类型
  • 类型断言能否成功,取决于变量的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互相转换