Head First Go - 第九部分定义类型

本文介绍了Go语言中如何定义自定义类型,如`Liters`和`Gallons`,并展示了如何使用类型转换和运算符。此外,还详细讲解了方法的定义,包括使用指针接收器来改变原始参数。最后,通过实例演示了如何通过方法实现不同单位之间的转换,如`CM`、`M`和`KM`。
摘要由CSDN通过智能技术生成


1. 定义和使用

定义结构:type 名字 类型

package main

import "fmt"

type Liters float64  //Liters就是float64类型
type Gallons float64 //Gallons就是float64类型

func main() {
	var carFuel Gallons //定义一个Gallons类型的
	var busFuel Liters  //定义一个Liters类型的

	//方法1:直接赋值
	carFuel = 3.14
	busFuel = 3.14

	//方法2:转化
	carFuel = Gallons(3.14)
	busFuel = Liters(3.14)

	fmt.Printf("carFuel: %v\n", carFuel) //carFuel: 3.14
	fmt.Printf("busFuel: %v\n", busFuel) //busFuel: 3.14
}

短变量声明:

package main

import "fmt"

type Liters float64  //Liters就是float64类型
type Gallons float64 //Gallons就是float64类型

func main() {
	carFuel := Gallons(3.14)
	busFuel := Liters(3.14)

	fmt.Printf("carFuel: %v\n", carFuel)	//carFuel: 3.14
	fmt.Printf("busFuel: %v\n", busFuel)	//busFuel: 3.14
}

注意的是不同类型不能相互赋值:
在这里插入图片描述

也可以这样写:

busFuel = Liters(Gallons(3.14))

有了这种写法,好处就是我们可以清晰知道一个数据的类型是什么类型,并且这个类型都有自己的含义



2. 定义类型和运算符

一个定义类型也可以使用基本运算符

package main

import "fmt"

type Liters float64  //Liters就是float64类型
type Gallons float64 //Gallons就是float64类型
type Title string

func main() {
	carFuel := Gallons(3.14)
	busFuel := Liters(3.14)

	fmt.Println(carFuel + Gallons(busFuel))	//6.28
	fmt.Println(carFuel - Gallons(busFuel))	//0
	fmt.Println(carFuel * Gallons(busFuel))	//9.8596
	fmt.Println(carFuel / Gallons(busFuel))	//1


	fmt.Println(Title("aaa") == Title("aaa"))	//true
	fmt.Println(Title("aaa") > Title("bbb"))	//false
	fmt.Println(Title("aaa") < Title("bbb"))	//true
	fmt.Println(Title("aaa") + Title("aaa"))	//aaaaaa

}



3. 使用函数进行转换

我们可以把转换的过程抽出来形成一个函数

package main

import "fmt"

type Liters float64  //Liters就是float64类型
type Gallons float64 //Gallons就是float64类型
type Title string

//Liters转化为Gallons
func ToGallons(l Liters) Gallons{
	return Gallons(l * 0.264)
}

//Gallons转化为Liters
func ToLiters(g Gallons) Liters{
	return Liters(g * 3.857)
}


func main() {
	carFuel := Gallons(3.14)
	busFuel := Liters(3.14)

	fmt.Println(ToGallons(busFuel))	
	fmt.Println(ToLiters(carFuel))

}

这样好处就是看起来方便一点,而且意思比较明确,但是我们知道 Gallons 不只是 Liters 能转化。比如米可以由里面转换,但是也可以由分米进行,但是Go语言不支持重载的操作,所以我们只能选择使用修改函数名的方法,但是如果由很多个单位转换,那我们就要设置很多个方法。接下来就来看看另一种解决方法:使用方法修复函数名冲突问题



4. 方法定义

方法定义和函数很类似,事实上,它们只有一点不同:你需要增加一个额外的参数,一个接收器参数,它在函数名称之前的括号中。下面例子中 sayHi 定义在了 MyType上面

package main

import "fmt"

type MyType string	//定义一个新的类型

//方法, 参数类型定义在函数名之前
func (m MyType) sayHi() {
	//输出接收器参数的值
	fmt.Println("Hi from", m)
}

func main() {
	value := MyType("Go")
	value.sayHi()	//Hi from Go
}

按照惯例,Go开发者通常使用一个字母作为名称 - 小写的接收器类型名称的首字母,比如MyType首写字母小写就是m。

那么能不能为所有类型定义新的方法?方法和类型定义必须同一个包,所以说那些不同包的自定义类型或者int等基本数据类型是不可以定义方法的



5. 方法和函数

事实上除了在接收器上被调用之外,方法和函数完全相同。就像函数一样,你也可以设置参数和返回值,并且方法名大写就是

package main

import "fmt"

type MyType string	//定义一个新的类型

//方法
func (m MyType) SayHello(name string, content string) string {
	fmt.Println("name: ", name, "content: ", content)
	fmt.Println("接收器参数: ", m)
	return "success"
}

func main() {
	value := MyType("Go")			//name:  张三 content:  aaa
	value.sayHello("张三", "aaa")	//接收器参数:  Go
}

这样看来方法就是和自定义类型进行绑定操作的了。



6. 指针类型的接收器参数

如果我们通过方法进行改变原参数,能不能呢?

package main

import "fmt"

type Number int

func (n Number) Double(){
	n *= 2
}

func main() {
	value := Number(4)
	value.Double()	//尝试加倍
	fmt.Printf("value: %v\n", value)	//value: 4
}

可以看到只是传入基本数据类型,那么结果还是不能加倍,这时候就可以使用指针了。

package main

import "fmt"

type Number int

func (n *Number) Double(){
	*n *= 2
}

func main() {
	value := Number(4)
	value.Double()	//尝试加倍
	fmt.Printf("value: %v\n", value)	//value: 8
}

下面这个例子也说明了,指针类型的参数也可以直接调用方法,Go会帮我们自动转化的,但是不建议这么使用,为了一致性,你所有的类型函数接受值类型或者都接收指针类型,应该避免混用的情况

package main

type Number int

func (n *Number) Double(){
	*n *= 2
}

func (n Number) Double2(){
	n *= 2
}


func main() {

	value := Number(4)
	pointValue := &value
	value.Double()	//尝试加倍
	value.Double2()	//尝试加倍
	pointValue.Double()
	pointValue.Double2()
}

最后注意一点:为了调用需要接收器指针的方法,我们需要获取这个值类型的指针

  1. &Number(4).Double2()这种写法是错误的
  2. Number(4).Double()这种也是错误的,必须先获取,再调用


7. 使用方法进行转换

package main

import "fmt"

type M float64
type CM float64
type KM float64

func (c CM) toM() M {
	return M(c / 100)
}

func (k KM) toM() M {
	return M(k * 1000)
}

func main() {
	m := CM(174)
	km := KM(1)

	height := m.toM()
	distance := km.toM()

	fmt.Printf("height: %v\n", height)		//height: 1.74
	fmt.Printf("distance: %v\n", distance)	//distance: 1000
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值