【Go系列】 Struct与interface

承上启下

        有了函数与方法,就应该介绍类这样一个东西,毕竟在面向对象语言中,对象就是基于类实现的。所以我们这一篇文章还是来介绍“类”。这时候会有点迷惑,不管是在当年学习C++还是JAVA的时候,我总会疑惑,有struct,有union,那么还要class这个东西干嘛?后来发现Class里面是包含方法的,逐渐发现他们的不同。但是,如果struct能够包含方法,那么和class又有什么不同呢,缺了继承(extend)和实现(implement),但是这些东西能不能用其他方法实现呢?

开始学习

struct(结构体)

Go语言中的struct是一种集合类型,它允许我们将多个不同类型的数据项组合成一个单一的数据结构。struct是Go实现面向对象编程的基础。

定义struct

type Person struct {
    Name string
    Age  int
}

使用struct

p := Person{Name: "Alice", Age: 30}
fmt.Println(p.Name) // 输出: Alice

 定义方法

package main

import (
    "fmt"
    "math"
)

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c *Circle) Scale(factor float64) {
    c.Radius *= factor
}

func main() {
    c := Circle{Radius: 5}
    fmt.Printf("Area of the circle: %v\n", c.Area())
    
    c.Scale(2)
    fmt.Printf("Area of the scaled circle: %v\n", c.Area())
}

在上面的例子中,Area 方法是一个值接收者方法,它返回圆的面积。Scale 方法是一个指针接收者方法,它修改圆的半径。

方法接收者的选择

  • 当结构体较小,或者不需要修改结构体的字段时,使用值接收者。
  • 当结构体较大,或者需要修改结构体的字段时,使用指针接收者,以避免不必要的内存拷贝。

方法重载(重载)

Go不支持传统意义上的方法重载,即不能有同名但参数列表不同的方法。但是,你可以通过为同一个类型定义多个方法,每个方法有不同的接收者类型(值接收者或指针接收者)来实现类似的效果。

嵌入类型(继承)

Go支持类型嵌入,允许你在一个结构体中嵌入另一个结构体或接口,这样嵌入的结构体或接口的方法就好像是外部结构体的方法一样。

type Wheel struct {
    Circle
    Spokes int
}

func (w Wheel) TotalArea() float64 {
    // Wheel 继承了 Circle 的方法
    return w.Area() + float64(w.Spokes)*w.Radius
}

在上述代码中,Wheel 结构体嵌入了 Circle 结构体,因此 Wheel 的实例可以直接调用 Circle 的方法。

通过以上介绍,我们可以看到Go语言中的struct方法为结构体提供了行为,使得结构体不仅仅是数据的集合,还具有操作数据的能力。这是Go实现面向对象编程的一个关键特性。

 

interface(接口)

Go语言的interface是一组方法的集合,它定义了一个对象的行为。任何类型只要实现了接口中定义的所有方法,就认为该类型实现了这个接口。

定义interface

type Animal interface {
    Speak() string
}

实现interface

type Dog struct{}

func (d Dog) Speak() string {
    return "Woof!"
}

func main() {
    var animal Animal = Dog{}
    fmt.Println(animal.Speak()) // 输出: Woof!
}

Go语言与其他面向对象语言的对比

struct的对比
  • Go vs. Java/C#

    在Java或C#中,类(Class)是面向对象的基础,它们可以包含字段(属性)和方法。Go则使用struct来定义数据结构,并通过方法来实现行为。Go的struct类似于Java/C#中的类,但没有继承的概念。

  • Go vs. C++

    C++中的结构体(struct)默认是public的,而Go的struct字段默认是私有的。在C++中,你可以使用类来定义具有方法的结构体,而在Go中,你直接在struct上定义方法。

interface的对比
  • Go vs. Java/C#

    Java和C#中的接口(Interface)与Go的interface类似,都是定义一组方法的集合。但是,Java和C#中的类可以实现多个接口,而Go中的类型也可以实现多个接口,但是Go没有显式的“implements”关键字。在Go中,实现接口是隐式的:只要一个类型实现了接口中定义的所有方法,它就自动实现了该接口。

  • Go vs. C++

    C++中的接口通常是通过抽象类实现的,其中包含纯虚函数。Go的interface则更轻量级,不需要显式的继承或实现声明。

特点对比
  • 继承

    Go不支持传统意义上的继承,而是通过组合(embedding)来实现代码复用。这与Java、C#和C++中的继承机制不同。

  • 多态

    Go的多态是通过interface实现的。在Java和C#中,多态通常是通过继承和接口共同实现的。C++则通过虚函数和继承实现多态。

  • 封装

    Go通过首字母大小写来控制字段和方法的可见性,这与Java、C#中的public、private、protected关键字不同。C++则使用作用域运算符和访问修饰符来控制封装。

总结

Go语言的设计哲学与传统的面向对象语言不同,它不提供传统的继承机制,而是使用组合(embedding)和接口来实现代码复用和多态。以下是Go在继承和接口方面的一些潜在缺点,以及相应的例子:

继承方面的缺点

1. 缺乏传统继承的直观性

Go不提供类和继承的概念,这可能会让从其他面向对象语言转过来的开发者感到不习惯。

type Base struct {
    BaseField int
}

func (b Base) BaseMethod() {
    // ...
}

type Derived struct {
    Base     // Go中的组合,类似于继承
    DerivedField int
}

func (d Derived) DerivedMethod() {
    // ...
}

在这个例子中,Derived 通过组合 Base 的字段和方法,但这不如传统继承直观。

2. 方法重写的不明确性

在Go中,没有明确的方法来重写嵌入类型的方法,这可能导致意外的行为。

func (d Derived) BaseMethod() {
    // 这不是传统意义上的方法重写,而是方法的重载
    // 这可能会导致开发者混淆
}

在这个例子中,Derived 类型定义了一个与 Base 类型同名的方法,但这并不是传统意义上的方法重写。

接口方面的缺点

1. 接口的隐式实现

Go中的接口是隐式实现的,这意味着任何类型只要实现了接口中的所有方法,就自动实现了该接口。这可能导致接口实现关系不明确。

type InterfaceA interface {
    MethodA()
}

type ConcreteType struct{}

func (ct ConcreteType) MethodA() {
    // ConcreteType隐式实现了InterfaceA
}

// 开发者可能不知道ConcreteType实现了InterfaceA接口,除非查看代码或文档。
2. 接口不支持方法的重载

Go的接口不支持方法重载,这意味着接口中的每个方法都必须有一个唯一的名称。

type InterfaceB interface {
    Method(int) // 接口中的方法不能有重载版本
    // Method(string) // 这是不允许的,会导致编译错误
}

在这个例子中,InterfaceB 接口不能有两个名为 Method 但参数类型不同的方法。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值