Loading...
Loading...
Loading...

目录


Golang入门-面向对象

计算机编程 发布于:2022/3/14/14:12 1042 vk go 最近编辑于2 年,9 月前 预计阅读时长:16min

 

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


 

单词数:436字符数:4853

共有0条评论