内容简介:参考type有如下几种用法:1.定义结构体
参考 Go关键字--type ,原文除类型定义外,还介绍了type其它几种使用场合。本文只说类型定义。
type有如下几种用法:
1.定义结构体
2.定义接口
3.类型定义
4.类型别名
5.类型查询
一、类型定义--------节选自《Go语言圣经》第69页
为了说明类型声明,我们将不同温度单位分别定义为不同的类型:
// Package tempconv performs Celsius and Fahrenheit temperature computations.
package tempconv
import "fmt"
type Celsius float64 // 摄氏温度
type Fahrenheit float64 // 华氏温度
const (
AbsoluteZeroC Celsius = -273.15 // 绝对零度
FreezingC Celsius = 0 // 结冰点温度
BoilingC Celsius = 100 // 沸水温度
)
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
我们在这个包声明了两种类型: Celsius和Fahrenheit分别对应不同的温度单位。它们虽然有着相同的底层类型float64,但是它们是不同的数据类型,因此它们不可以被相互比较或混在一个表达式运算。刻意区分类型,可以避免一些像无意中使用不同单位的温度混合计算导致错误; 因此需要一个类似Celsius(t)或Fahrenheit(t)形式的显式转型操作才能将float64转为对应的类型。Celsius(t)和Fahrenheit(t)是类型转换操作,它们并不是函数调用。类型转换不改变值本身,但是会使它们的语义发生变化。另一方面,CToF和FToC两个函数则是对不同温度单位下的温度进行换算,它们会返回不同的值。
对于每一个类型T,都有一个对应的类型转换操作T(x),用于将x转为T类型(译注:如果T是指针类型,可能会需要用小括弧包装T,比如 (*int)(0) )。只有当两个类型的底层基础类型相同时,才允许这种转型操作,或者是两者都是指向相同底层结构的指针类型,这些转换只改变类型而不会影响值本身。如果x是可以赋值给T类型的值,那么x必然也可以被转为T类型,但是一般没有这个必要。
数值类型之间的转型也是允许的,并且在字符串和一些特定类型的slice之间也是可以转换的,在下一章我们会看到这样的例子。这类转换可能改变值的表现。例如,将一个浮点数转为整数将丢弃小数部分,将一个字符串转为 []byte 类型的slice将拷贝一个字符串数据的副本。在任何情况下,运行时不会发生转换失败的错误(译注: 错误只会发生在编译阶段)。
底层数据类型决定了内部结构和表达方式,也决定是否可以像底层类型一样对内置运算符的支持。这意味着,Celsius和Fahrenheit类型的算术运算行为和底层的float64类型是一样的,正如我们所期望的那样。
fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C
boilingF := CToF(BoilingC)
fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
比较运算符 == 和 < 也可以用来比较一个命名类型的变量和另一个有相同类型的变量,或有着相同底层类型的未命名类型的值之间做比较。但是如果两个值有着不同的类型,则不能直接进行比较:
var c Celsius var f Fahrenheit fmt.Println(c == 0) // "true" fmt.Println(f >= 0) // "true" fmt.Println(c == f) // compile error: type mismatch fmt.Println(c == Celsius(f)) // "true"!
注意最后那个语句。尽管看起来想函数调用,但是Celsius(f)是类型转换操作,它并不会改变值,仅仅是改变值的类型而已。测试为真的原因是因为c和g都是零值。
二、类型定义让代码更加简洁
使用类型定义定义出来的类型与原类型不相同,所以不能使用新类型变量赋值给原类型变量,除非使用强制类型转换。下面来看一段示例代码,根据string类型,定义一种新的类型,新类型名称是name:
type name string
为什么要使用类型定义呢?类型定义可以在原类型的基础上创造出新的类型,有些场合下可以使代码更加简洁,如下边示例代码:
package main
import (
"fmt"
)
// 定义一个接收一个字符串类型参数的函数类型
type handle func(str string)
// exec函数,接收handle类型的参数
func exec(f handle) {
f("hello")
}
func main() {
// 定义一个函数类型变量,这个函数接收一个字符串类型的参数
var p = func(str string) {
fmt.Println("first", str)
}
exec(p)
// 匿名函数作为参数直接传递给exec函数
exec(func(str string) {
fmt.Println("second", str)
})
}
输出信息是:
first hello second hello
上边的示例是类型定义的一种简单应用场合,如果不使用类型定义,那么想要实现上边示例中的功能,应该怎么书写这段代码呢?
// exec函数,接收handle类型的参数
func exec(f func(str string)) {
f("hello")
}
exec函数中的参数类型,需要替换成func(str string)了,咋一看去也不复杂,但是假如exec接收一个需要5个参数的函数变量呢?是不是感觉参数列表就会很长了。
func exec(f func(str string, str2 string, num int, money float64, flag bool)) {
f("hello")
}
从上边的代码可以发现,exec函数的参数列表可读性变差了。下边再来看看使用类型定义是怎么实现这个功能:
package main
import (
"fmt"
)
// 定义一个需要五个参数的函数类型
type handle func(str string, str2 string, num int, money float64, flag bool)
// exec函数,接收handle类型的参数
func exec(f handle) {
f("hello", "world", 10, 11.23, true)
}
func demo(str string, str2 string, num int, money float64, flag bool) {
fmt.Println(str, str2, num, money, flag)
}
func main() {
exec(demo)
}
三、 详解 Go 语言中的 time.Duration 类型
在 Time 包中,定义有一个名为 Duration 的类型和一些辅助的常量:
type Duration int64
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
然后是测试代码:
func Test() {
var waitFiveHundredMillisections int64 = 500
startingTime := time.Now().UTC()
time.Sleep(10 * time.Millisecond)
endingTime := time.Now().UTC()
var duration time.Duration = endingTime.Sub(startingTime)
var durationAsInt64 = int64(duration)
if durationAsInt64 >= waitFiveHundredMillisections {
fmt.Printf("Time Elapsed : Wait[%d] Duration[%d]\n",
waitFiveHundredMillisections, durationAsInt64)
} else {
fmt.Printf("Time DID NOT Elapsed : Wait[%d] Duration[%d]\n",
waitFiveHundredMillisections, durationAsInt64)
}
}
运行了这段测试代码,然后得到了下面的输出,从输出内容来看,我定义的 500 毫秒的时间已经用完了,但怎么可能。
Time Elapsed : Wait[500] Duration[10724798]
从上面的知识很容易看出问题, Duration 类型中时间的基本单位是 Nanosecond ,所以当我将一个表示 10 毫秒的 Duration 类型对象转换为 int64 类型时,我实际上得到的是 10,000,000。
改成这样测试一下
func Test() {
var waitFiveHundredMillisections time.Duration = 500 * time.Millisecond
startingTime := time.Now().UTC()
time.Sleep(600 * time.Millisecond)
endingTime := time.Now().UTC()
var duration time.Duration = endingTime.Sub(startingTime)
if duration >= waitFiveHundredMillisections {
fmt.Printf("Wait %v\nNative [%v]\nMilliseconds [%d]\nSeconds [%.3f]\n",
waitFiveHundredMillisections, duration, duration.Nanoseconds()/1e6, duration.Seconds())
}
}
实际上, Duration 类型拥有一些便捷的类型转换函数,它们能将 Duration 类型转化为 Go 语言的内建类型 int64 或 float64 ,像下面这样:
func Test() {
var duration_Seconds time.Duration = (1250 * 10) * time.Millisecond
var duration_Minute time.Duration = 2 * time.Minute
var float64_Seconds float64 = duration_Seconds.Seconds()
var float64_Minutes float64 = duration_Minute.Minutes()
fmt.Printf("Seconds [%.3f]\nMinutes [%.2f]\n", float64_Seconds, float64_Minutes)
}
我也迅速注意到了在时间转换函数中,并没有转换毫秒值的函数,使用 Seconds 和 Minutes 函数,我得到了如下输出:
Seconds [12.500] Minutes [2.00]
但我需要转换毫秒值,为什么包里面单单没有提供毫秒值的转换呢?因为 Go 语言的设计者希望我有更多的选择,而不只是将毫秒值转换成某种单独的内建类型。下面的代码中,我将毫秒值转化为了 int64 类型和 float64 类型:
func Test() {
var duration_Milliseconds time.Duration = 500 * time.Millisecond
var castToInt64 int64 = duration_Milliseconds.Nanoseconds() / 1e6
var castToFloat64 float64 = duration_Milliseconds.Seconds() * 1e3
fmt.Printf("Duration [%v]\ncastToInt64 [%d]\ncastToFloat64 [%.0f]\n",
duration_Milliseconds, castToInt64, castToFloat64)
}
我将纳秒值除以 1e6 得到了 int64 类型表示的毫秒值,将秒值乘以 1e3 ,我得到了 float64 类型表示的毫秒值,上面代码的输出如下:
Duration [500ms] castToInt64 [500] castToFloat64 [500]
参考一下内置包time中的源码,很容易理解:
func (d Duration) Seconds() float64 {
sec := d / Second
nsec := d % Second
return float64(sec) + float64(nsec)/1e9
}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 番外篇2-基本规范、注释、static关键字、import关键字
- 说说iOS中的常用的关键字static ,class(仅限Swift关键字)
- Golang 关键字
- 2019 关键字
- golang关键字
- final关键字深入解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Sovereign Individual
James Dale Davidson、William Rees-Mogg / Free Press / 1999-08-26 / USD 16.00
Two renowned investment advisors and authors of the bestseller The Great Reckoning bring to light both currents of disaster and the potential for prosperity and renewal in the face of radical changes ......一起来看看 《The Sovereign Individual》 这本书的介绍吧!