GoLang之对象

GoLang之面向对象

Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。

类方法

在Go语言中,可以给任意类型(包括内置类型,但不包括指针类型)添加相应的方法。

如下面的这个例子,定义了一个新类型Integer,它和int一样,只是为它内置的int类型增加了个新方法Less()

type Integer int 

func (a Integer) Less(b Integer) bool {
    return a < b
}

func main() {
    var a Integer = 1 

    if a.Less(2) {
        fmt.Println("less then 2")
    }
}

可以看出,Go语言在自定义类型的对象中没有C++/Java那种隐藏的this指针,而是在定义成员方法时显式声明了其所属的对象。

如果要修改对象的值,可以传递对象的指针

func (a *Ingeger) Add(b Integer) {
    *a += b
}

func main() {
    var a Integer = 1
    a.Add(3)
    fmt.Println("a =", a)     //  a = 4
}

如果Add方法不使用指针,则a返回的结果不变,这是因为Go语言函数的参数也是基于值传递。

之前说过,Go语言没有构造函数的概念,通常使用一个全局函数来完成。例如:

func NewRect(x, y, width, height float64) *Rect {
    return &Rect{x, y, width, height}
}   

func main() {
    rect1 := NewRect(1,2,10,20)
    fmt.Println(rect1.width)
}

匿名组合

Go语言提供了继承,但是采用了组合的语法,我们将其称为匿名组合,例如:

type Base struct {
    name string
}

func (base *Base) Set(myname string) {
    base.name = myname
}

func (base *Base) Get() string {
    return base.name
}

type Derived struct {
    Base
    age int
}

func (derived *Derived) Get() (nm string, ag int) {
    return derived.name, derived.age
}

func main() {
    b := &Derived{}

    b.Set("sina")
    fmt.Println(b.Get())
}

例子中,在Base类型定义了get()和set()两个方法,而Derived类型继承了Base类,并改写了Get()方法,在Derived对象调用Set()方法,会加载基类对应的方法;而调用Get()方法时,加载派生类改写的方法。

组合的类型和被组合的类型包含同名成员时, 会不会有问题呢?可以参考下面的例子:

type Base struct {
    name string
    age int
}

func (base *Base) Set(myname string, myage int) {
    base.name = myname
    base.age = myage
}

type Derived struct {
    Base
    name string
}

func main() {
    b := &Derived{}

    b.Set("sina", 30)
    fmt.Println("b.name =",b.name, "\tb.Base.name =", b.Base.name)
    fmt.Println("b.age =",b.age, "\tb.Base.age =", b.Base.age)
}

值语义和引用语义

值语义和引用语义的差别在于赋值,比如

b = a
b.Modify()

如果b的修改不会影响a的值,那么此类型属于值类型;如果会影响a的值,那么此类型是引用类型。

Go语言中的大多数类型都基于值语义,包括:

  • 基本类型,如byte、int、bool、float32、string等;
  • 复合类型,如arry、struct、pointer等;

C语言中的数组比较特别,通过函数传递一个数组的时候基于引用语义,但是在结构体定义数组变量的时候基于值语义。而在Go语言中,数组和基本类型没有区别,是很纯粹的值类型,例如:

var a = [3] int{1,2,3}
var b = a
b[1]++
fmt.Println(a, b)   // [1 2 3] [1 3 3]

从结果看,b=a赋值语句是数组内容的完整复制,要想表达引用,需要用指针:

var a = [3] int{1,2,3}
var b = &a    // 引用语义
b[1]++
fmt.Println(a, b)   // [1 3 3] [1 3 3]

接口

Interface 是一组抽象方法(未具体实现的方法/仅包含方法名参数返回值的方法)的集合,如果实现了 interface 中的所有方法,即该类/对象就实现了该接口。

Interface 格式:

type interfaceName interface {
    //方法列表
}  

Interface 可以被任意对象实现,一个类型/对象也可以实现多个 interface;
不支持方法重载;

时间: 2025-01-01 10:37:29

GoLang之对象的相关文章

golang 复制对象的正确做法

需求 实际运用种,传参是一对象指针,现在如何最简便地复制一对象? 实现 坑:&*  先拿到值再指针? package main import ( "time" "log" ) func main() { T1 := &TestS{1} T2 := &*T1 T2.a = 5 log.Print(T1) log.Print(T2) } 输出 2017/06/15 20:14:27 &{5} 2017/06/15 20:14:27 &am

深入Golang之sync.Pool详解

我们通常用golang来构建高并发场景下的应用,但是由于golang内建的GC机制会影响应用的性能,为了减少GC,golang提供了对象重用的机制,也就是sync.Pool对象池. sync.Pool是可伸缩的,并发安全的.其大小仅受限于内存的大小,可以被看作是一个存放可重用对象的值的容器. 设计的目的是存放已经分配的但是暂时不用的对象,在需要用到的时候直接从pool中取. 任何存放区其中的值可以在任何时候被删除而不通知,在高负载下可以动态的扩容,在不活跃时对象池会收缩. sync.Pool首先

golang中interface接口的深度解析

什么是interface,简单的说,interface是一组method的组合,下面这篇文章主要给大家深度解析了关于golang中的interface接口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧. 一 接口介绍 如果说gorountine和channel是支撑起Go语言的并发模型的基石,让Go语言在如今集群化与多核化的时代成为一道亮丽的风景,那么接口是Go语言整个类型系列的基石,让Go语言在基础编程哲学的探索上达到前所

GO语言的进阶之路-面向对象编程

GO语言的进阶之路-面向对象编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 当你看完这篇文章之时,我可以说你的Golang算是入门了,何为入门?就是你去看Docker 源码能看懂60%的语法结构,因为涉及一些unix的代码可能没有Linux运维基础的同学在学习的时候会很吃力,看起来也会带来一定的难度,如果有时间的话我会给大家解析Docker部门精辟的源码.好了,回归正题吧,我们今天要学习的内容是什么呢?即面向对象编程.当然,不要用屌丝的心态来说:"那要是没对象的还咋编程呢

Springboot 系列(二)Spring Boot 配置文件

注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 不管是通过官方提供的方式获取 Spring Boot 项目,还是通过 IDEA 快速的创建 Spring Boot 项目,我们都会发现在 resource 有一个配置文件 application.properties,也有可能是application.yml.这个文件也就是 Spring Boot 的配置文件. 1. YAML 文件 在 Sp

【GoLang】golang 如何像Java 一样通过类名反射对象?

结论: golang不支持解析string然后执行. golang的反射机制只能存在于已经存在的对象上面. 不知道后续的版本有没有规划,现在只能先加载注册,然后实现类似Java工厂模式的反射. 代码示例: t := reflect.ValueOf(Human{}).Type() // h := reflect.New(t).Elem() // new return address pointer h := reflect.New(t).Interface() fmt.Println(h) hh

golang在多个go routine中进行map或者slice操作应该注意的对象。

因为golang的map和列表切片都是引用类型,且非线程安全的,所以在多个go routine中进行读写操作的时候,会产生"map read and map write"的panic错误. 某一些类型的对象,会有这种类似的set方法来写数据,或者get方法来返回一个map: func (this *object) Set(name, val) { this.Lock() defer this.Unlock() this.m[name] = val } func (this *objec

【玩转Golang】 自定义json序列化对象时,非法字符错误原因

由于前台web页面传来的日期对象是这样的格式“2010-11-03 15:23:22”,所以我安装网上查来的办法,自定义包装了time.Time对象,实现自己的Marshal和UnMarshal方法 type DateTime struct { time.Time } const ctLayout = "2006-01-02 15:04:05" const ctLayout_nosec = "2006-01-02 15:04" const ctLayout_date

嵌套Golang对象的初始化

  比如有这样一个对象: type ProductConfig struct {     Site map[string]string } 对应的初始化可以如下写: var pc ProductConfig pc = ProductConfig{Site: map[string]string{"rakuten": "http://item.rakuten.co.jp/auc-trustgift/10079213/",     "tmail": &