Go中的方法:
方法的定义与任何其他Go函数一样。当Go函数在有限范围内定义或附加特定类型时,它被称为方法。方法提供了一种向用户定义类型添加行为的方法。方法实际上是包含一个额外参数的函数,该参数在关键字func和函数名称之间声明。
在Go中,方法是一种特殊的函数,它作用于某种类型的变量,称为接收器,它是放置在方法名称之前的额外参数,用于指定方法附加到的目标类型。接收器类型可以是任何东西,而不仅仅是结构类型:任何类型都可以有方法,甚至是函数类型或int、bool、string或数组的别名类型。
方法的一般格式为:
func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }
接收器在 ( ) 中指定,在func关键字之后的方法名称之前。
下面是非结构类型的方法示例:
关键字func和函数名称之间的参数称为接收器,并将函数绑定到指定的类型。当函数具有接收器时,该函数称为方法。
Go中有两种类型的接收器:值接收器和指针接收器。在上面的程序中,tentimes方法使用值接收器声明。multiply接收器被声明为int类型的值。使用值接收器声明方法时,该方法将始终针对用于进行方法调用的值的副本进行操作。
mul变量初始化为multiply类型。因此,当我们调用tentimes方法时,可以使用mul.tentimes() 访问tentimes方法,mul的值是调用的接收器值,tentimes方法正在该值的副本上运行。
package main
import "fmt"
type multiply int
func (m multiply) tentimes() int {
return int(m * 10)
}
func main() {
var num int
fmt.Print("Enter any positive integer: ")
fmt.Scanln(&num)
mul:= multiply(num)
fmt.Println("Ten times of a given number is: ",mul.tentimes())
}
输出:
Enter any positive integer: 5
Ten times of a given number is: 50
下面是一个程序,它通过receiver参数(称为类型的方法集)显示附加到类型的方法数的实现。
package main
import "fmt"
type salary float64
func (s salary) total() total {
return total(s)
}
type total float64
func (t total) hra() hra {
t += t * 0.3 // 30% HRA Addition
return hra(t)
}
func (t total) salary() salary {
t -=t * 0.10 // 10% Tax Deduction
return salary(t)
}
type hra float64
func (h hra) basic() basic {
h += h * 0.3 // 30% HRA Addition
return basic(h)
}
func (h hra) total() total {
return total(h)
}
type basic float64
func (b basic) total() total {
return total(b)
}
func main() {
fmt.Println("Salary calculation for First Employee:")
sal1 := basic(9000.00)
fmt.Println(sal1.total())
fmt.Println(sal1.total().hra().total())
fmt.Println(sal1.total().hra().total().salary())
fmt.Println("\nSalary calculation for Second Employee:")
sal2 := basic(5000.00)
fmt.Println(sal2.total())
fmt.Println(sal2.total().salary())
}
输出:
Salary calculation for First Employee:
9000
11700
10530
Salary calculation for Second Employee:
5000
4500
方法重载:
方法重载是可能的,具有相同名称的方法可以存在于2种不同的接收器类型上,Receiver参数可以作为基类型的值或指针传递。指针接收器参数在Go中应用广泛。
示例代码:
package main
import "fmt"
type multiply int
type addition int
func (m *multiply) twice() {
*m = multiply(*m * 2)
}
func (a *addition) twice() {
*a = addition(*a + *a)
}
func main() {
var mul multiply = 15
mul.twice()
fmt.Println(mul)
var add addition = 15
add.twice()
fmt.Println(add)
}
输出:
30
30
使用指针接收器声明方法的示例。
在main() 中,我们自己不必弄清楚是否在指针上调用方法,Go为我们做到了这一点。mul1是一个值,mul2是一个指针,但方法调用工作得很好。
package main
import "fmt"
type multiply struct {
num int
}
func (m *multiply) twice(n int) {
m.num = n*2
}
func (m multiply) display() int{
return m.num
}
func main() {
fmt.Println("Call by value")
var mul1 multiply // mul1值类型mul1.twice(10)
fmt.Println(mul1.display())
fmt.Println("Call by pointer")
mul2 := new(multiply) // mul2指针类型mul2.twice(10)
fmt.Println(mul2.display())
}
输出:
Call by value
20
Call by pointer
20
Go中的对象:
在Go中,没有类类型作为对象基础的概念。Go中的任何数据类型都可以用作对象。Go中的struct类型可以接收一组方法来定义其行为。GO中不存在称为类或对象的特殊类型。Go中的strct类型与其他编程语言中通常称为对象的东西相吻合。Go支持通常归因于面向对象编程的大多数概念。
在包和可扩展类型系统等概念的帮助下,Go的核心支持物理和逻辑模块化;因此,我们能够在Go中实现模块化和封装。
新声明的名称类型不会继承其基础类型的所有属性,并且类型系统会以不同的方式处理。因此,GO不支持通过继承进行多态性。但是,可以使用结构体或接口等类型通过组合来创建对象并表达其多态关系。
让我们从下面的简单例子开始,来演示如何将结构类型用作可以实现多态组合的对象。
示例代码:
package main
import "fmt"
type gadgets uint8
const (
Camera gadgets = iota
Bluetooth
Media
Storage
VideoCalling
Multitasking
Messaging
)
type mobile struct {
make string
model string
}
type smartphone struct {
gadgets gadgets
}
func (s *smartphone) launch() {
fmt.Println ("New Smartphone Launched:")
}
type android struct {
mobile
smartphone
waterproof string
}
func (a *android) samsung() {
fmt.Printf("%s %s\n",
a.make, a.model)
}
type iphone struct {
mobile
smartphone
sensor int
}
func (i *iphone) apple() {
fmt.Printf("%s %s\n",
i.make, i.model)
}
func main() {
t := &android {}
t.make ="Samsung"
t.model ="Galaxy J7 Prime"
t.gadgets = Camera+Bluetooth+Media+Storage+VideoCalling+Multitasking+Messaging
t.launch()
t.samsung()
}
输出:
New Smartphone Launched:
Samsung Galaxy J7 Prime
在上面的程序中,使用组合继承原则,利用结构类型支持的类型嵌入机制实现多态性。在这里,每种类型都是独立的,并且被认为与所有其他类型不同。上面的程序表明,iphone和android类型是通过子类型关系的移动的。
然而,被调用的t.launch() 方法,无论是iphone还是android,都不是名为launch() 的方法的接收器。launch() 方法是为智能手机类型定义的。由于智能手机类型嵌入在iphone和android类型中,因此launch() 方法在范围内被提升到这些封闭类型,因此可以访问。