Golang 复合数据类型:方法

攻壳机动队
• 阅读 2968

传统的面向对象编程

在面向对象编程(OOP)中,类与对象是面向对象编程的两个主要方面。一个类(Class)能够创建一种新的类型(Type),其中对象(Object)就是类的实例(Instance)。可以这样来类比:你可以拥有类型 int 的变量,也就是说存储整数的变量是 int 类的实例(对象)。

对象可以使用属于它的普通变量来存储数据。这种从属于对象或类的变量叫作字段(Field)。对象还可以使用属于类的函数来实现某些功能,这种函数叫作类的方法(Method)。这两个术语很重要,它有助于我们区分函数与变量,哪些是独立的,哪些又是属于类或对象的。总之,字段与方法通称类的属性(Attribute)

方法

在 Golang 中,方法是作用在接收者(receiver)上的一个函数,接收者是某种类型的变量;接收者可以是任意类型(指针、接口除外),包括结构体类型、函数类型、可以是 int ,boll,string或数组别名类型。

  • 接收者不能是一个接口类型,因为接口是一个抽象定义,方法却必须要具体实现
  • 接收者不能是一个指针类型,但可以是任何其他类型允许的指针

方法重载

类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在不同的源文件中,唯一的要求是它们必须是同一个包的。 因为方法是函数,所以同样的,不允许方法重载,即对于一个类型只能有一个给定名称的方法,但是如果基于接收器类型,是有重载的。如下面的例子,具有同样名字的方法Add可以在 2 个或多个不同的接收器类型*denseMatrix*sparseMatrix上存在,比如在同一个包里这么做是允许的:

//a是接收器变量,*denseMatrix和*sparseMatrix是接收器类型,Add是方法,b Matrix是参数列表,Matrix是返回参数
func (a *denseMatrix) Add(b Matrix) Matrix
func (a *sparseMatrix) Add(b Matrix) Matrix

接收器的标准格式

  • recv是接收器名称,receiver_type是接收器类型( 接收器中的参数变量名在命名时,官方建议使用接收器类型名的第一个小写字母 ,例如 Socket 类型的接收器变量应该命名为 s )
  • methodName是方法名,paramater_list是参数列表,return_value_list是返回值列表
func (recv receiver_type)methodName(paramater_list)(return_value_list) {...}

接收器的类型

在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器,大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。

  • 指针类型

    由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self;但 Go 并没有 this 和 self 这两个关键字,因此,也可以使用 this 和 self 作为接收者的实例化名字(this 和 self 跟一般的实例化名字没什么两样)。

    //定义TwoInts结构体
    type TwoInts struct {
        a int
        b int
    }
    func main(){
        two1 := new(TwoInts)//实例化,返回指针*TwoInts
        two1.a = 12
        two1.b = 10
        //调用AddThem方法
        fmt.Println(two1.AddThem())
        //调用AddToParam方法
        fmt.Println(two1.AddToParam(20))
    
        two2 := TwoInts{3,4} //实例化,返回结构体TwoInts{3,4}
        //调用AddThem方法
        fmt.Println(two2.AddThem())
    }
    //指针接收器的两个值相加方法
    func (tn *TwoInts)AddThem()int{
        return tn.a + tn.b
    }
    //指针接收器的三个值相加方法
    func (tn *TwoInts)AddToParam(param int)int{
        return tn.a + tn.b + param
    }
    
    /*
    22
    42
    7
    */

    代码说明:

    • 定义一个TwoInts结构,拥有两个整型的成员变量。使用名字two1实例化TwoInts结构体,返回指针类型*TwoInts,分别设置实例化成员变量two1.atwo1,b的值为1210;使用名字two2实例化TwoInts结构体,设置成员变量返回结构体TwoInts
    • 构造成员变量的方法AddThem,设置方法的接收器类型为指针*TwoInts,返回tn.a + tn.b 的整型值;因此可以修改成员值,即便退出方法,也有效;构造另一个成员变量的方法AddToParam,设置方法的接收器类型为指针*TwoInts,返回tn.a + tn.b + param的整型值。
    • main函数中,使用fmt.Println函数分别调用AddThemAddToParam方法,获取成员变量的值。
  • 非指针类型

    当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效

    // 定义点结构
    type Point struct {
        X int
        Y int
    }
    // 非指针接收器的加方法
    func (p Point) Add(other Point) Point {
        // 成员值与参数相加后返回新的结构
        return Point{p.X + other.X, p.Y + other.Y}
    }
    func main() {
        // 初始化点
        p1 := Point{3, 4}
        p2 := Point{2, 5}
        // 与另外一个点相加
        result := p1.Add(p2)
        // 输出结果
        fmt.Println(result.X,result.Y,result)
    }
    
    /*
    5 9 {5 9}
    */

    代码说明:

    • 定义一个Point点结构,拥有XY两个整型的成员变量
    • Point结构定义一个非指针接收器的Add方法,传入和返回都是Point的结构,可以方便地实现多个点连续相加的效果,例如P4 := P1.Add( P2 ).Add( P3 )
    • p1p2实例化两个点
    • p1p2两个点相加后返回结果并存储到result
    • 打印结果resultXY相加的值

      由于例子中使用了非指针接收器,Add() 方法变得类似于只读的方法,Add() 方法内部不会对成员进行任何修改

### 函数和方法的区别

函数将变量作为参数:Function(recv);方法在变量上被调用:recv.Method1()

  • 当接收者是指针时,方法可以改变接收者的值和状态。(对于方法来说)
  • 当参数作为指针传递时,即通过引用调用时,函数也可以改变参数的状态。(对于函数来说)

### Golang设计模式之工厂方法

参考链接:Golang设计模式之工厂方法(掘金)

在面向对象编程中,可以通过构造子方法实现工厂模式,但 Golang 并不是面向对象编程语言,因此不能使用构造子方法来实现设计模式,而是相应地提供了其他方案。以结构体为例,通常会为结构体类型定义一个工厂,工厂的名字以new或者New开头。

//不强制构造函数,首字母大写
type File struct {
    fd int
    name string
}

//构造工厂方法
func NewFile(fd int,name string) *File{
    if fd < 0 {
        return nil
    }
    return &File{fd,name}
}

func main() {
    //调用工厂方法NewFile
    f := NewFile(10,"./test.yxy")
    fmt.Println(f)
    //计算结构体占用多少内存
    size := unsafe.Sizeof(File{})
    fmt.Println(size)
}

/*
&{10 ./test.yxy}
24
*/

代码说明:

  • 以首字母为大写,不强制使用构造函数,创建结构体File
  • 为这个结构体构造一个工厂方法NewFile,并返回指向结构体的指针*File
  • main函数调用该工厂方法

强制使用工厂方法,通过应用可见性就可以禁止使用new函数,强制用户使用工厂方法,从而使类型转变成私有的。

### 指针或值作为接收者

如果想要方法改变接收者的数据,就在接收者的指针类型上定义该方法。否则,就在普通的值类型上定义方法。

change()接收一个指向B的指针,并改变它的内部成员;write()通过拷贝接收B的值并只输出B的内容,

  type B struct {
      thing int
  }
  
  func (b *B) change() {
      b.thing = 1
  }
  
  func (b B) write() string { 
      return fmt.Sprint(b) 
  }
  
  func main() {
      var b1 B // b1是值
      b1.change()
      fmt.Println(b1.write())
  
      b2 := new(B) // b2是指针
      b2.change()
      fmt.Println(b2.write())
  }
  
  /* 
  {1}
  {1}
  */
点赞
收藏
评论区
推荐文章
半臻 半臻
4年前
Python基础6——面向对象
14面向对象14.1面向对象基础​面向对象是一种编程思想,处理面向对象编程以外,还有面向过程编程​三大特征:1.封装2.继承3.多态​面向过程与面向对象的区别1.面向过程:自己动手洗衣服,拧衣服、晾衣服2.面向对象:构造一个洗衣机对象,让洗衣机对象完成14.2类和对象​类:相同属性和功能的一类事物。​人是一个类,张三(
菜园前端 菜园前端
2年前
什么是面向对象编程?
原文链接:什么是面向对象编程?面向对象程序设计(ObjectOrientedProgramming,OOP)是一种计算机编程架构,也可以理解为是一种编程的思想。面向对象程序设计的核心就是对象和类,对象也是类的实例化,类是对现实对象的抽象。对象间通过消息传递
Bill78 Bill78
4年前
Python入门之类(class)
Python3面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对
Easter79 Easter79
4年前
TypeScript 中的类和接口
在面向对象(OOP)编程中,经常会使用到class(类)和interface(接口)。在TypeScript(以下简称TS)中也引入了类和接口的概念,使得TS强大的类型检测机制更加完善。就像我们所知道的,一个类是一堆抽象概念的集合,我们可以从类的构造方法中创建出享有共同属性和方法的对象。一个接口所描述的是一个对象相关的属性和方法,但并不提供具体创建此对象实例
Wesley13 Wesley13
4年前
JAVA类和对象创建
!(https://oscimg.oschina.net/oscnet/22ac82441e269125878e950d13f2825b44f.jpg)  面向对象  学习目标:  理解面向对象的编程思想  理解类与对象的关系  如何创建类与对象  方法重载  一:什么是面向对象编程(OOP)  面向对象编程(Object
Wesley13 Wesley13
4年前
Java增强的包装类
java语言是面向对对象的编程语言,但这八种基本数据类型不支持面向对对象的编程的机制,基本数据类型的数据不具备“对象”的特征:没有成员变量、方法可以调用。java提供这8中基本数据类型,主要是为了照顾程序员的传统的习惯。但这也带来了麻烦,因为所有的引用类型都继承来自Object的类,可当成object的类型使用,所以当一个方法的参数是object类型参数时候
Wesley13 Wesley13
4年前
Java总论及三大特性理解
1、对象(object)   万物皆为对象(根类Object类)。   程序是对象的集合(面向对象程序设计语言OOP)。   每个对象都有自己的由其他对象所构成的存储(对象有成员属性)。   每个对象都拥有其类型(每个对象都是某个类class的一个实例instance)。某一特定类型的所有对象都可以接收
Stella981 Stella981
4年前
Javascript 面向对象编程
Javascript面向对象编程(一):封装Javascript是一种基于对象(objectbased)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。那么,如果我们要把"属性
小万哥 小万哥
1年前
深入解析 Java 面向对象编程与类属性应用
Java面向对象编程面向对象编程(OOP)是一种编程范式,它将程序组织成对象。对象包含数据和操作数据的方法。OOP的优势:更快、更易于执行提供清晰的结构代码更易于维护、修改和调试提高代码重用性减少开发时间类和对象类是对象的模板,它定义了对象的属性和方法。对
小万哥 小万哥
1年前
Kotlin 面向对象编程 (OOP) 基础:类、对象与继承详解
面向对象编程(OOP)是一种编程范式,它通过创建包含数据和方法的对象来组织代码。相较于过程式编程,OOP提供了更快更清晰的结构,有助于遵守DRY(Don&39;tRepeatYourself)原则,使代码更易于维护和扩展。在Kotlin中,类和对象是OOP的核心。类作为对象的模板,定义了对象的行为和状态;对象则是类的具体实例。例如,Car类可以定义汽车的品牌、型号等属性,以及如驾驶和刹车等功能。通过构造函数可以快速初始化对象的属性。此外,Kotlin支持继承机制,子类可以从父类继承属性和方法,促进代码重用。
攻壳机动队
攻壳机动队
Lv1
寂寞空庭春欲晚,梨花满地不开门。
文章
1
粉丝
0
获赞
0
热门文章

暂无数据