struct
首先了解一下如何自定义一个数据类型
package main
import "fmt"
type myint int //定义了一个叫myint的数据类型,它的类型还是int只不过名字变了
func main() {
var a myint = 10 //可以在变量定义的时候使用
fmt.Println(a)
fmt.Printf("type of a =%T\n", a) //printf是格式化输出,printin是打印出来的东西会带空格,自动换行,print是不会自动换行,中间也没空格
//fmt.Println("go","python","php","javascript") // go python php javascript
//fmt.Print("go","python","php","javascript") // gopythonphpjavascript
}
再来看一下,定义一个结构体实际上和定义一个新的数据类型差不多,只不过定义的时候多了些属性
package main
import "fmt"
type book struct {
title string
auth string
}
func main() {
var mybook book
mybook.title = "java"
mybook.auth = "vk"
fmt.Println(mybook)
}
当然要是想通过函数修改book的属性的话传入指针就行,不清楚怎么传入指针的时候可以看上一篇基础语法:go入门|基础语法
类的表示与封装
GO是通过结构体初始化一个类,定义类的名字,并且定义一些属性,然后通过函数在传入参数的时候把类的指针传入修改,展示,增加,删除等对类进行一些操作了。注意!如果函数传入参数之传类名字是值拷贝,无法对类的属性做出操作的。初始化一个类的时候只需要和其他语言一样创建就行。不管是类名还是属性,还是类方法,只要是大写的话就表示其他包/外部也可以访问,小写的话就是这个模块/内部私有的
package main
import "fmt"
type Book struct {
Title string
Auth string
}
func (this *Book) Show() { //this是变量名字可以随便起
fmt.Println(this.Title)
}
func (this *Book) SetName(Newname string) { //这里Book得用*传入才能修改值
this.Auth = Newname
}
func main() {
mybook := Book{Title: "java", Auth: "vk"}
mybook.Show()
mybook.SetName("kv")
fmt.Println(mybook.Auth)
}
继承
现在我们定义一个yellowbook (黄页)对象,它继承父类Book ,并且有自己新增的属性,和重写父类的方法
package main
import "fmt"
type Book struct {
Title string
Auth string
}
type YellowBook struct {
Book //继承了父类Book
page int
}
func (this *Book) Show() { //this是变量名字可以随便起
fmt.Println(this.Title)
}
func (this *Book) SetName(Newname string) { //这里Book得用*传入才能修改值
this.Auth = Newname
}
//重写父类Book的show方法
func (this *YellowBook) Show() {
fmt.Println("yellowbook is show")
}
func main() {
//定义子类对象
var yellow YellowBook
yellow.page = 66
yellow.Title = "go"
yellow.Auth = "vk"
fmt.Println(yellow)
yellow.Show()
}
多态
所谓多态就是一个接口,多种实现。比如一个有一个动物接口,定义了三个方法:sleep(),eat(),run()。那么任何一个动物就都要满足这三个方法。但是又很多种实现,羊可以睡觉吃饭,跑人也可以睡觉吃饭跑。
在定义一个类的时候没必要继承这个接口,只需要实现了接口里面的方法就行。注意!必须实现父类(接口)的全部方法才行,接口本质上是一个指针,调用的时候指向了具体的子类
package main
import "fmt"
//本质是指针
type Animal interface {
Eat() string
Run()
Sleep()
}
type Person struct {
//无需继承接口实现接口的方法即可
food string
}
func (this *Person) Sleep() {
fmt.Println("a man is sleeping")
}
func (this *Person) Eat() string {
fmt.Println("a man is eating ", this.food)
return this.food
}
func (this *Person) Run() {
fmt.Println("a man is running")
}
type Sheep struct {
//无需继承接口实现接口的方法即可
food string
}
func (this *Sheep) Sleep() {
fmt.Println("a Sheep is sleeping")
}
func (this *Sheep) Eat() string {
fmt.Println("a Sheep is eating ", this.food)
return this.food
}
func (this *Sheep) Run() {
fmt.Println("a Sheep is running")
}
func main() {
var animal Animal //接口的数据类型为 父类指针
animal = &Person{"apple"}
animal.Sleep() //调用的是Person的sleep,多态的体现
animal.Eat()
animal = &Sheep{"grass"}
animal.Sleep() //调用的是Sheep的sleep,多态的体现
animal.Eat()
}
输出的结果是

Interface空接口万能类型
package main
import "fmt"
func God(arg interface{}) {
//可以传入任何类型
fmt.Println("god is called")
//内置断言机制可以判断传入的参数是什么类型
value, ok := arg.(string) //判断是否为字符串
if !ok {
fmt.Println("arg is not string")
} else {
fmt.Println("arg is string")
fmt.Println("arg=", value)
}
}
type Man struct {
auth string
}
func main() {
man := Man{"go"}
God(man)
God("123")
God(1.11)
}
结果长这样

我试了以下,value, ok := arg.(string) 这里如果ok是❌的话,value全部返回了“”(空字符串)。
反射
在go语言中一个变量内部构造其实有两部分,类型和值,我们是可以通过反射来得到变量的类型或值的。

可以通过reflect包里面的函数valueof,typeof,method得到变量的值,类型,方法
package main
import (
"fmt"
"reflect"
)
func reflectNum(arg interface{}) {
fmt.Println(reflect.TypeOf(arg))
fmt.Println(reflect.ValueOf(arg))
}
func main() {
var num int = 12
reflectNum(num)
}
比如想得到一个结构体内变量的类型和值如果里面有多个属性,直接typeof肯定得到是一堆数据类似:{int string xxx}这种。
可以用for循环,类似与反向查询这种,把每个字段的各种信息都分别提取出来。NumField()函数是计算出reflect返回的对象里有多少个字段,用法就是xxx.Numfield(),相应的还有NumMethod(),有多少个方法。
func getfiled(input interface{}) {
inputType := reflect.TypeOf(input)
inputValue := reflect.ValueOf(input)
for i := 0; i < inputType.NumField(); i++ { //numfiled计算总共多长
field := inputType.Field(i) //获取字段
fieldname := field.Name //获取字段名字
value := inputValue.Field(i).Interface() //通过interface获取值
typefield := field.Type //获取类型
fmt.Println(fieldname, value, typefield)
}
}
比如这个函数,如果传入的参数input是一个结构体这种的话,里面有很多属性方法什么的,通过reflect.TypeOf(input)得到的肯定不止一个值,想要分别表示的话就用一个for循环这么取就行
结构体标签
结构体标签就是给每个属性加了个标签,比如json解析的时候,想在json里解析为title:'go',但是结构体里定义的是Title string这种,它是大写的json解析时不想把它弄成大写。
这时候就可以给属性设置一个键值对:
type Movie struct {
Title string `json:"title"`
}
!!!注意tag那里这个不是单引号,是键盘左上角Esc下方的那个键,英文的。
package main
import (
"encoding/json"
"fmt"
)
type Movie struct {
Title string `json:"title"`
}
func main() {
movie := Movie{"当幸福来敲门"}
//编码过程
jsonStr, _ := json.Marshal(movie) //_匿名变量,第二个返回值是error,也可以加上判断编码的时候出错没
//if error !=nil {xxxx}
fmt.Printf("%s", jsonStr)
//解码同理,用函数json.Unmarshal
}
想通过反射获取结构体的标签也很简单,xxx.Field(i).Tag.get("json")这种写法获取就行
go的面向对象就介绍到这里了。
下一篇是《go高级goroutine和channel》