GO语言扩展已有类型|青训营

71 阅读7分钟

GO语言扩展已有类型|青训营

当我们使用别人的包的时候,如果我们想要拓展一个已有类型,在其他面向对象的语言中,只需要继承一下即可,但是在继承的过程中会遇到很多的不灵活。在GO语言中取消了继承,他有两种方法来扩充别人的类型(或系统类型):

定义别名

在Go语言中,可以使用别名来扩展或拓展已有类型。通过使用别名,您可以为现有的类型创建新的名称,并在新的名称上定义新的方法。这样做的好处是,您可以在不修改原始类型的情况下,为其添加新的功能或行为。

下面是使用别名拓展已有类型的步骤:

  1. 定义别名:使用type关键字创建一个新的类型,并给它起一个新的名字。这个新的名字就是别名。

  2. 定义新方法:在新的别名类型上定义新的方法,这些方法将成为该别名类型的特有行为。

拓展内置类型int

下面是一个示例,展示如何拓展Go语言的内置类型int

package main

import "fmt"

// 定义一个新的类型别名,取名为MyInt
type MyInt int

// 在MyInt类型上定义一个新的方法Double,用于将值翻倍
func (m MyInt) Double() MyInt {
	return m * 2
}

func main() {
	// 使用别名类型创建变量
	num := MyInt(5)

	// 调用MyInt类型上的方法
	doubledNum := num.Double()

	// 输出结果
	fmt.Println("原始值:", num)
	fmt.Println("翻倍后的值:", doubledNum)
}

在上面的例子中,我们定义了一个新的类型别名MyInt,它是基于内置类型int创建的。然后,我们在MyInt类型上定义了一个新的方法Double,用于将值翻倍。在main函数中,我们创建一个MyInt类型的变量num,并调用它的Double方法,将其值翻倍,并输出结果。

注意:尽管我们使用了别名拓展int类型,但是别名类型MyInt和原始类型int是不同的类型。虽然它们在底层具有相同的表示和相互转换的能力,但是它们在Go语言中是不可互换的类型。

拓展已有结构体

当使用结构体时,也可以使用别名来拓展已有结构体的功能。以下是一个使用别名拓展结构体的例子:

package main

import "fmt"

// 定义一个Person结构体
type Person struct {
	Name    string
	Age     int
	Country string
}

// 在Person结构体上定义一个新的方法PrintDetails,用于打印个人信息
func (p Person) PrintDetails() {
	fmt.Printf("Name: %s\nAge: %d\nCountry: %s\n", p.Name, p.Age, p.Country)
}

// 定义一个新的类型别名,取名为Employee
type Employee Person

// 在Employee类型上定义一个新的方法SetEmployeeID,用于设置员工ID
func (e Employee) SetEmployeeID(id int) {
	fmt.Printf("Setting Employee ID %d for %s\n", id, e.Name)
}

func main() {
	// 创建一个Person结构体对象
	person := Person{
		Name:    "Alice",
		Age:     30,
		Country: "USA",
	}

	// 调用Person结构体上的方法
	person.PrintDetails()

	// 使用Employee类型创建一个新的对象
	employee := Employee{
		Name:    "Bob",
		Age:     25,
		Country: "Canada",
	}

	// 调用Employee类型上的方法
	employee.PrintDetails()
	employee.SetEmployeeID(1001)
}

在上面的例子中,我们首先定义了一个Person结构体,其中包含NameAgeCountry三个字段,并定义了一个方法PrintDetails()用于打印个人信息。接下来,我们通过将Person类型赋值给一个新的类型别名Employee来创建一个新的类型。这样一来,Employee类型就具有了Person结构体的所有字段和方法。

main函数中,我们创建了一个Person类型的对象person和一个Employee类型的对象employee。然后,我们调用了它们各自的方法,包括PrintDetails()方法和SetEmployeeID()方法,展示了如何使用别名类型拓展已有结构体的功能。

使用组合

当使用组合来拓展已有类型时,我们不会使用别名,而是在新的结构体中嵌入一个已有类型,并通过这种嵌入的方式来继承已有类型的字段和方法。这种方式通常称为组合或嵌套结构体。

下面是使用组合扩展已有类型的步骤:

  1. 定义新的结构体:使用type关键字定义一个新的结构体,并在其中嵌入一个已有类型。这个已有类型可以是一个自定义结构体、内置类型或其他的扩展结构体。

  2. 使用已有类型:在新的结构体中可以直接使用已有类型的字段和方法,就像它们是新结构体的一部分一样。

下面是一个示例,展示如何使用组合扩展已有结构体的功能:

package main

import "fmt"

// 定义一个Person结构体
type Person struct {
	Name    string
	Age     int
	Country string
}

// 在Person结构体上定义一个方法PrintDetails,用于打印个人信息
func (p Person) PrintDetails() {
	fmt.Printf("Name: %s\nAge: %d\nCountry: %s\n", p.Name, p.Age, p.Country)
}

// 定义一个新的结构体Employee,嵌入了Person结构体
type Employee struct {
	Person
	EmployeeID int
}

// 在Employee结构体上定义一个新的方法SetEmployeeID,用于设置员工ID
func (e Employee) SetEmployeeID(id int) {
	fmt.Printf("Setting Employee ID %d for %s\n", id, e.Name)
}

func main() {
	// 创建一个Employee结构体对象
	employee := Employee{
		Person: Person{
			Name:    "Alice",
			Age:     30,
			Country: "USA",
		},
		EmployeeID: 1001,
	}

	// 调用Employee结构体上的方法
	employee.PrintDetails()
	employee.SetEmployeeID(1002)
}

在上面的例子中,我们定义了一个Person结构体,并在其上面定义了一个PrintDetails()方法。然后,我们定义了一个新的结构体Employee,并在其中嵌入了Person结构体,同时添加了一个新的字段EmployeeID

main函数中,我们创建了一个Employee结构体的对象employee,并直接使用Person结构体的字段和方法,包括PrintDetails()方法和Name字段。同时,我们也调用了Employee结构体自己的方法SetEmployeeID()。这样,我们通过组合的方式扩展了Person结构体的功能,让Employee结构体具有了Person结构体的所有功能,并且在此基础上添加了新的字段和方法。

总结

当使用Go语言来拓展已有类型时,有两种常见的方式:

  1. 使用别名拓展已有类型:

    • 使用type关键字创建一个新的类型别名,将其赋值为已有类型。
    • 在新的类型别名上定义新的方法,用于添加新的功能或行为。
    • 这种方式创建的别名类型和原始类型是不可互换的,尽管它们在底层具有相同的表示和相互转换的能力。
  2. 使用组合扩展已有类型:

    • 使用type关键字定义一个新的结构体,并在其中嵌入一个已有类型。
    • 在新的结构体中可以直接使用已有类型的字段和方法,就像它们是新结构体的一部分一样。
    • 这种方式创建的新结构体可以直接使用已有类型的功能,并在此基础上添加新的字段和方法。

在示例代码中,我们展示了这两种方式的用法:

  1. 使用别名拓展已有类型的示例代码展示了如何在int类型上定义一个新的类型别名MyInt,并在其上面定义新的方法Double()用于翻倍操作。

  2. 使用组合扩展已有类型的示例代码展示了如何在Person结构体上定义一个新的结构体Employee,并在其中嵌入Person结构体,同时添加新的字段EmployeeID和方法SetEmployeeID()

无论使用别名还是组合,都能让我们在不修改原有类型的情况下,为其添加新的功能或行为。选择哪种方式取决于您的需求和设计考虑。使用别名适用于需要对现有类型进行一些扩展,而使用组合适用于创建一种新的、拥有已有类型功能的复合类型。