GO基本语法学习之路 Day2

GO基本语法学习之路 Day2

1. 面向对象的封装

GO语言中没有类的概念,也不支持类的继承等面向对象的概念。GO语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

结构体的定义

// 结构体的定义
type hero struct {
	name string
	ad	int
	level int
}

如果类名首字母大写,表示其他包也能够访问,和函数一样,即全局类;
如果类的属性首字母大写,表示对其他包是public的,否则则是private的,只能自己包使用
如果类的方法首字母大写,表示当前方法在其他包也能访问,这一点都是通用的

通过上面也能看出,go的封装是针对包来封装的。

结构体方法的创建

func (this hero) show() {
	fmt.Println("NAME = ", this.name)
	fmt.Println("ad = ", this.ad)
	fmt.Println("level = ", this.level)
}

// 结构体的方法
func (this hero) GetName() string {
	
	return this.name
}

func (this hero) SetName(name string) {
	this.name = name
}

创建一个对象:这里类似于C++中的初始化构造,大括号里面加入键值对,当然也可以省略键值对

func main() {
	// 创建一个对象
	h := hero{name:"JehanRio", ad:21, level:1}
	// h := hero{"JehanRio", 21, 1}	// 这样也可以
	h.show()
}
/*
运行结果:
NAME =  JehanRio
ad =  21
level =  1
*/

需要注意的是,this会对对象进行拷贝,所以你修改的数据是无法做到的,除非把this换为指针,即func(this *hero) SetName

func (this* hero) SetName(name string) {
	this.name = name
}

func main() {
	// 创建一个对象
	h := hero{name:"JehanRio", ad:21, level:1}
	h.show()
	h.SetName("Bjergsen")
	h.show()
}

在这里插入图片描述

2. 面像对象继承

与类不同,Go语言中没有类的概念,也没有类的继承。但可以通过嵌套结构体来实现类似继承的效果。通过在一个结构体中嵌套另一个结构体,可以继承嵌套结构体的字段和方法,俗称套娃。。。

不过我觉得更像是组合,而不是继承。

同时,子类也可以重写父类方法

package main
import "fmt"

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{name:"JehanRio", sex:"man"}
	h.Eat()
	h.Walk()
	fmt.Println("____________________________")
	s := SuperMan{Human{"JehanRio", "man"}, 99}
	s.Walk()
	s.Eat()
	s.Fly()
}

3. 多态interface

相当于C++的抽象类+子类。在GO里面就相当于定义了全局的一些虚函数

package main

import "fmt"

// 本质是一个指针
type animalIF interface {
	sleep()
	getColor() string	
	getType() string
}

// 具体的类
type cat struct {
	color string
	
}
func (this *cat) sleep() {
	fmt.Println("cat is sleeping")
}
func (this *cat) getColor() string {
	return this.color
}
func (this *cat) getType() string {
	return "cat"
}

// 具体的类
type dog struct {
	color string
	
}
func (this *dog) sleep() {
	fmt.Println("dog is sleeping")
}
func (this *dog) getColor() string {
	return this.color
}
func (this *dog) getType() string {
	return "dog"
}

func showAnimal(animal animalIF) {
	animal.sleep()	// 多态调用
	fmt.Println("color : ", animal.getColor())
	fmt.Println("type : ", animal.getType())
}

func main() {
	// var animal animalIF
	// animal = &cat{"red"}	// interface本身是一个指针,必须传地址
	// animal.sleep()	// 调用cat的sleep

	c := cat{"red"}
	d := dog{"yellow"}
	showAnimal(&c)	
	showAnimal(&d)	
}

任何语言的多态思想都是通用的,父类 = new 子类这种,即子类能转换为父类。

所以go的多态基本要素为:

  • 有一个父类(有接口)
  • 有子类(实现父类的全部接口方法)
  • 父类类型的变量(指针)=(指针)子类的具体数据变量

4. 通用万能类型与类型断言

interface{},常用类型都实现了interface,和Python的Object有点像。

这里还出现了类型断言,他可以判断interface的底层类型是什么,具体用法看代码。

package main

import "fmt"

func myFunc(arg interface{}) {
	fmt.Println("myFunc is called")
	fmt.Println(arg)

	// interface{} 该如何区分 此时引用的底层数据类型是什么?

	// 给interface{} 提供了“类型断言”的机制
	value, ok := arg.(string)	// 会返回两个值
	if !ok {
		fmt.Println("arg is not string type")
	} else {
		fmt.Println("arg is string type, value = ", value)
		fmt.Printf("value type is %T\n", value)
	}
}

type book struct {
	author string
}

func main() {
	b := book{"JehanRio"}
	myFunc(b)
	myFunc("3.14")
}

在这里插入图片描述

5. 变量的内置pair结构

GoLang中的变量组成:
在这里插入图片描述
go里面的断言就是类型转换,转换的时候会把type和value一起变换,变换方法为w = r.(Writer)

断言的时候分两步:

  1. 得到动态类型 type
  2. 判断 type 是否实现了目标接口

下面的例子中,我们的变量b,类型是Book类型,是一个接口,而这个类型实现了两个方法,分别是ReadBook()WriteBook(),所以在断言时,才能从reader类型变为Writer类型(若将WriteBook()的实现注释掉,则会断言失败!)

type reader interface {
	ReadBook()
}

type Writer interface {
	WriteBook()
}

type Book struct {

}

func (this *Book) ReadBook() {
	fmt.Println("Read a book")
}

func (this *Book) WriteBook() {
	fmt.Println("write a book")
}

func main() {
	b := &Book{}	// b: pair<type:Book, value:Book{}地址> 相当于子类,需要使用地址,才能被父类接收

	var r reader	// r: pair<type:, value:>	一开始为空
	r = b	

	r.ReadBook()

	var w Writer
	w = r.(Writer)	// 此处的断言为什么会成功? 断言有两步:1. 得到动态类型 type,2. 判断 type 是否实现了目标接口。这里断言成功是因为 type 是 Book,而 Book 实现了 Writer 接口
	w.WriteBook()
}

7. 区分一下类型断言和类型转换

类型断言

var greeting interface{} = "hello world"
greetingStr := greeting.(string)

类型转换

greeting := []byte("hello world")
greetingStr := string(greeting)

最明显的不同是它们有着不同的语法: variable.(type) vs type(variable)

首先,类型断言只能作用在接口上,以检查其是否实现了期望的接口或者具体的类型,类型断言有两种用法:

<目标类型的值><布尔参数> := <表达式>.( 目标类型 ) // 安全类型断言
<目标类型的值> := <表达式>.( 目标类型 )  //非安全类型断言

总的来说,类型转换就是从一个确定类型转换为另一个确定类型;而类型断言就是将一个未知类型(interface{})转换为一个确定类型。

Go语言类型转换和断言有什么区别?

8. 反射reflect机制

interface及其pair的存在,是Golang中实现反射的前提,理解了pair,就更容易理解反射。反射就是用来检测存储在接口变量内部(值value;类型concrete type) pair对的一种机制。

reflect的基本功能TypeOf和ValueOf


// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i.  ValueOf(nil) returns the zero 
func ValueOf(i interface{}) Value {...}

//ValueOf用来获取输入参数接口中的数据的值,如果接口为空则返回0


// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {...}

//TypeOf用来动态获取输入参数接口中的值的类型,如果接口为空则返回nil

reflect.TypeOf()是获取pair中的type,reflect.ValueOf()获取pair中的value,例子如下:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var num float64 = 1.2345

    fmt.Println("type: ", reflect.TypeOf(num))
    fmt.Println("value: ", reflect.ValueOf(num))
}

运行结果:
type:  float64
value:  1.2345

说明

  1. 转换的时候,如果转换的类型不完全符合,则直接panic,类型要求非常严格!
  2. 转换的时候,要区分是指针还是值
  3. 也就是说反射可以将“反射类型对象”再重新转换为“接口类型变量”

9. 结构体标签

作用是在别的包在使用你的包的时候,能进行解释。

package main

import (
	"fmt"
	"reflect"
)

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.NumField(); i++ {
		taginfo := t.Field(i).Tag.Get("info")
		tagdoc := t.Field(i).Tag.Get("doc")
		fmt.Println("info: ", taginfo, "tag:", tagdoc)
	}
}

func main() {
	var re resume
	findTag(&re)
}
Go言是一种静态类型、编译型的编程语言,它支持面向对象、过程式和函数式编程范式。以下是Go语言的一些基本语法: 1. 变量声明和赋值 Go语言中的变量声明和赋值使用关键字var和:=符号。例如: ``` var a int a = 10 b := "hello, world!" ``` 2. 控制流语句 Go语言中的控制流语句包括if、for、switch和select。例如: ``` if a > 0 { fmt.Println("a is positive") } else { fmt.Println("a is non-positive") } for i := 0; i < 10; i++ { fmt.Println(i) } switch day { case "Monday": fmt.Println("Today is Monday") case "Tuesday": fmt.Println("Today is Tuesday") default: fmt.Println("Today is another day") } select { case msg1 := <-ch1: fmt.Println("Received message from ch1:", msg1) case msg2 := <-ch2: fmt.Println("Received message from ch2:", msg2) default: fmt.Println("No message received") } ``` 3. 函数定义和调用 Go语言中的函数定义使用关键字func,函数调用使用函数名和参数列表。例如: ``` func add(a, b int) int { return a + b } sum := add(1, 2) fmt.Println(sum) ``` 4. 结构体和方法 Go语言中的结构体定义使用关键字type,方法定义使用关键字func和结构体类型。例如: ``` type Person struct { Name string Age int } func (p *Person) SayHello() { fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.Name, p.Age) } person := Person{Name: "Alice", Age: 25} person.SayHello() ``` 这些是Go语言的一些基本语法,当然还有很多其他的语法特性和细节需要了解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值