栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

Golang——面向对象编程(上)

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Golang——面向对象编程(上)

Go面向对象说明
  1. Golang 也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以我们说 Golang 支持面向对象编程特性是比较准确的。
  2. Golang 没有类(class),Go 语言的结构体(struct)和其它编程语言的类(class)有同等的地位,可以理解 Golang 是基于 struct 来实现 OOP 特性的。
  3. Golang 面向对象编程非常简洁,去掉了传统 OOP 语言的继承、方法重载、构造函数和析构函数、隐藏的 this 指针等等
  4. Golang 仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它 OOP 语言不一样,比如继承 :Golang 没有 extends 关键字,继承是通过匿名字段来实现。
  5. Golang 面向对象(OOP)很优雅,OOP 本身就是语言类型系统(type system)的一部分,通过**接口(interface)**关联,耦合性低,也非常灵活。也就是说在Golang 中面向接口编程是非常重要的特性。
结构体

结构体是值类型,默认为值拷贝。除非使用指针进行拷贝,为引用,修改指针引用的变量,原结构体也会随之改变

结构体中的指针,切片,映射的默认值均为nil,未分配空间,如果要使用,应首先进行make

声明结构体
type 结构体名称 struct { 
	field1 type
	field2 type
}
创建结构体变量和访问结构体字段

方法一:直接声明

var person Person

方法二:{ }

var person Person = Person{field,field}

方法三:&

var person *Person = new (Person)

方法四:&、{ }

var person *Person = &Person{field,field}
说明
  1. 第 3 种和第 4 种方式返回的是 结构体指针。

  2. 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名

    (*person).Name = "tom"
    
  3. 但 go 做了一个简化,也支持 结构体指针.字段名

    person.Name = "tom"
    

    更加符合程序员使用的习惯,go 编译器底层 对person.Name 做了转化 (*person).Name。

使用细节
  1. 结构体的所有字段在内存中是连续的
  2. 结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)
  3. 结构体进行 type 重新定义(相当于取别名),Golang 认为是新的数据类型,但是相互间可以强制类型转换

4.struct 的每个字段上,可以写上一个 tag, 该 tag 可以通过反射机制获取,常见的使用场景就是序列化和反序列化。

type Person struct{
	Name string `ison:"name"`
	Age int `json:"age"`
}
person := Person{"lzq",18}
//将变量序列化为JSON格式字串
//json.Marshal函数中使用反射
jsonStr,err := json.Marshal(person)
if err != nil{
    fmt.Prinln("json处理错误",err)
}
fmt.Prinln("jsonStr",string(jsonStr))
方法

在某些情况下,我们要需要声明(定义)方法。比如 Person 结构体:除了有一些字段外( 年龄,姓名…),Person 结构体还有一些行为比如:可以说话、跑步…,通过学习,还可以做算术题。这时就要用方法才能完成。

Golang 中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型, 都可以有方法,而不仅仅是 struct。

方法的声明和调用
type Person struct { 
	Name int
}
func (p Person) test() { 
    fmt.Println("test() name=",p.Name)
}
//调用
func main(){
    var p Person
    p.Name="lzq"
    p.test()//调用方法
}

test( )方法和Person类型绑定

test方法只能通过Person类型的变量来调用,而不能直接调用,也不能使用其他类型变量来调用

var dog Dog
dog.test()
test()//这两种调用方式都是错误的
方法可以传入参数、返回值
func(p Person) calculate(n int) res int
方法的调用和传参机制原理(重要!!)

方法的调用和传参机制和函数基本一样,不一样的地方是方法调用时,会将调用方法的变量,当做实参也传递给方法。

如以下代码

func(p Person) calculate(n int) res int{
	res:= 0
	for i:=1;i<=n;i++{
		res += i
	}
	return res
}
func main(){
    var p Person
    n:=2
    res := calculate(n)
    fmt.Prinln(res)
}

程序运行过程中会先为main函数创建一个栈区

main栈

p—>[lzq] Name

n—>[2]

res:=30

再调用calculate方法并传入实参

calculate栈

p—>[lzq] Name

n—>[2]

return 6

方法的注意事项和细节
  1. 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
  2. 修改结构体变量的值,可以通过结构体指针的方式来处理
func (p *Person) modify() {
    p.Name ="xmy"
}//此处的p.Name等价于(*p).Name
var p Person
p.Name ="lzq"

3.Golang 中的方法作用在指定的数据类型上的(即和指定的数据类型绑定),因此自定义类型, 都可以有方法,而不仅仅是 struct, 比如 int , float32 等都可以有方法

//在其他数据类型中使用方法
package main
import (
	"fmt"
)
type integer int
func (i integer) print() {
	fmt.Println("i=",i)
}
func ( i *integer) change(){
	*i+=1
}
func main() {
	var i integer = 10
	i.print()
	i.change()
	fmt.Println("i=",i)
	
}

4.方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。
5.如果一个类型实现了 String()这个方法,那么 fmt.Println 默认会调用这个变量的 String()进行输出

type Student struct{
	Name string
	Age int
}
//给*string实现方法String()
func (stu *Student) String() string{
    str := fmt.Sprintf("Name=[%v] Age=[%v]",stu.Name,stu.Age)
    return str
}
func main(){
    stu := Student{
   		Name : "lzq",
   		Age : 18,
	}
	fmt.Println(&stu)
}
方法和函数的区别
  1. 调用方式不一样

    1. 函数的调用方式: 函数名(实参列表)
    2. 方法的调用方式: 变量.方法名(实参列表)
  2. 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然

  3. 方法(如 struct 的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以


    上图揭示了方法传参的特点。

  1. 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定.
  2. 如果是和值类型,比如 (p Person) , 则是值拷贝, 如果和指针类型,比如是 (p *Person) 则是地址拷贝。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/907970.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号