前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go语言学习-面相对象 原

go语言学习-面相对象 原

作者头像
solate
发布2019-07-19 18:39:34
7040
发布2019-07-19 18:39:34
举报
文章被收录于专栏:solate 杂货铺solate 杂货铺

go 面相对象

只保留了组合(composition)这个最基础的特性

对象传递

Go语言和C语言一样,类型都是基于值传递的。要想修改变量的值,只能传递指针。

Go语言中的面向对象最为直观,也无需支付额外的成本。如果要求对象必须以指针传递, 这有时会是个额外成本,因为对象有时很小(比如4字节),用指针传递并不划算。

只有在你需要修改对象的时候,才必须用指针

代码语言:javascript
复制
var a Integer = 1 //传入b=2
func (a *Integer) Add(b Integer) {
    *a += b // 执行方法后 a=3
}

// 如果传入的不是指针则方法外部a的值不变,相当于值传递


func (a Integer) Add(b Integer) { 
    a += b // 执行后a在外面不变 a=1 
}

值语义 和 引用语义

代码语言:javascript
复制
b=a
修改b,a值不变 值语义
修改b,a值改变 引用语义

go中数组为值语义

代码语言:javascript
复制
var a = [3]int{1, 2, 3}
var b = a
b[1]++
fmt.Println(a, b) //结果 [1 2 3] [1 3 3]

var a = [3]int{1, 2, 3}
var b = &a //b为a的引用
b[1]++
fmt.Println(a, *b) //结果 [1 3 3] [1 3 3]

或
var a = []int{1, 2, 3} // slice a 本身就是引用
var b = a //b的值直接就是引用
b[1]++
fmt.Println(a, *b) //结果 [1 3 3] [1 3 3]

go中四种引用类型

  • 数组切片(slice):指向数组(array)的一个区间。
  • map:极其常见的数据结构,提供键值查询能力。
  • channel:执行体(goroutine)间的通信设施。
  • 接口(interface):对一组满足某个契约的类型的抽象。

struct

初始化方式

  1. new : rect1 := new(Rect)
  2. rect2 := &Rect{} //rect2 引用,
  3. rect3 := Rect{} // rect3 值

指针方法和struct方法

  • struct方法类似于类方法, struct和实例都能用
  • 指针方法类似于对象方法,只有实现的实例可以用
代码语言:javascript
复制
package main

import ()
import "fmt"

type Dept struct {
	name     string
	building string
	floor    uint8
}

func (self Dept) Name() string {
	return self.name
}

func (self Dept) SetName(name string) {
	self.name = name
}

func (self *Dept) Relocate(building string, floor uint8) {
	self.building = building
	self.floor = floor
}

func main() {
	dept1 := Dept{name: "MySohu", building: "Media", floor: 7}
	dept1.Relocate("Media", 12) //实例调用指针方法
}

依据Go语言规范:

如果结构的实例x是"可被寻址的",且&x的方法集中包含方法m,则 x.m()为(&x).m()的速记(快捷方式)。

即:dept1是可被寻址的,且&dept1的方法集中包含方法Relocate(),则 dept1.Relocate()为&dept1.Relocate()的快捷方式。

组合

代码语言:javascript
复制
type Foo struct {
    ... //
    Base
}

//也有形如下面这种,只是Foo创建实例的时候,需要外部提供一个Base类 实例的
type Foo struct {
    ... //
    *Base
}
//这种方式可以很容易的借到定义类型的方法

eg:

type Job struct {
    Command string
    *log.Logger
}

func (job *Job)Start() {
    //借用log.Logger的方法,实际还是使用原有log.Logger的方法,因此不能访问到Job中的其他属性
    job.Log("starting now...") 
    ... //做事情
    job.Log("started.")
}
代码语言:javascript
复制
//匿名组合类型相当于以其类型名称(去掉包名部分) 作为成员变量的名字。按此规则,Y类型中就相当于存在两个名为Logger的成员,虽然类型不同。 因此,我们会收到编译错误。
type Logger struct {
    Level int
}
type Y struct {
    *Logger
    Name string
    *log.Logger
}

//这个编译错误并不是一定会发生的。 如这两个Logger在定义后再也没有被用过,那么编译器将直接  忽略掉这个冲突问题,直到开发者开始使用其中的某个Logger。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • go 面相对象
    • 对象传递
      • 值语义 和 引用语义
        • struct
          • 初始化方式
          • 指针方法和struct方法
          • 组合
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档