Go基础-007 类型描述

2020-02-23  本文已影响0人  如逆水行舟不进则退

1.变量强类型

变量在声明时,需要明确指定其类型,一旦定义不可改变。
变量,仅仅可以存储对应的类型的数据!

2.静态类型和动态类型

关于变量的类型,其中声明类型称之为静态类型,而真实值类型我们称之为动态类型。
典型的数据类型变量的静态和动态类型保持一致。例如 var x int; x = 42;

// 保持一致 动静一致
var x int // x 的静态类型是 
int x = 42 // x 的动态类型是 int

注意:在一种叫做接口的数据类型上,动态类型和静态类型不一致。
优势是 在处理动态数据时,需要在运行时确定数据的真实类型。此时,需要一个机制来处理,所以使用空接口进行处理。

3.空接口,interface{},任意类型

接口,interface,本质用来定义一组操作。

空接口,没有定义任何操作的接口,该接口满足任何类型的定义。
字面量如下: interface{}

空接口的意义在于,可以定义一个变量为空接口类型,使用该变量存储任意的数据数据类型。

代码:

// x 的静态类型是 interface{} 
var x interface{}
// 赋值为 42 int 型
x = 42 
fmt.Println(x)

// 赋值 "hank" string 型 
x = "hank"
fmt.Println(x)
// 赋值 false bool 型
x = false 
fmt.Println(x) 

其中,x 变量的静态类型 interface{}空接口,而动态类型,随着其赋值而定,分别为 int, string,bool 型。

注意:空接口 interface{} 也是一种数据类型,虽然可以被赋值为 int,string 或其他类型 的数据,但是 interface{} 与其他类型不一致,是一种独立的类型。即使我们将字符串类型 赋值给了空接口类型变量,也不能与字符串类型直接做运算,
代码演示:

var x interface{}
// 赋值 "hank" string 型
x = "hank"
fmt.Println(x + " " + "GoLang")
// 报错:# command-line-arguments
// .\type.go:28:16: invalid operation: x + " GoLang" (mismatched types interface {} and string)

若需要真正的获取空接口变量中存储的特定类型的数据,需要使用类型断言或类型检测 来实现。

4.类型断言

用于断定空接口中的数据是何种类型,断定成功,会获取该类型的数据,断定失败,获
取不成功。 语法如下:

代码演示:

var x interface{}
// 赋值 "hank" string 型
x = "hank"

// 断言为字符串类型,不获取断言结果,通常在可以从逻辑上确定数据类型
时使用。
sx := x.(string) 
fmt.Printf("%T\n", sx)  // string
fmt.Println(sx) // hank
var y interface{} 
y = 42

// 断言为字符串类型,需要获取断言结果,通常在不能判断是否为我们需要
的数据类型时使用。提供了错误处理 
sy, e := y.(string) 
fmt.Println(e) // false

// 当断言失败时,人为处理需要的数据 
if !e { // 断言失败
   sy = "default string" 
}
fmt.Println(sy) // default string

5.类型测试

可以通过 interface.(type) (type 就是 type 关键字,不是数据类型的意思)与 switch 结
构配合使用,完成类型检测。
代码演示:

var x interface{} 
x = 42
// x = "hank"
// x = false
switch d := x.(type) { 
case int:
  fmt.Println(d, d+42)  // 42 84
case string:
  fmt.Println(d, d + " GoLang")  // hank  hank Golang
case bool:
  fmt.Println(d, !d)  // false true
}

注意: 这种语法 和 switch 的常规语法不一致,是一种特殊的语法

6.类型转换

将通过 A 类型的数据,得到 B 类型的数据,该转换过程,称之为类型转换。 语法:
B 类型数据 = B 类型标识(A 类型数据)

代码演示:

// 类型转换
var x int = 42
var y float64 = 42.5 
fmt.Println(float64(x) + y) //  84.5

若不转换,语法检测失败,不同类型不能计算:
invalid operation: x + y (mismatched types int and float64)

典型的转换情况:

        // 类型转换
    var x int = 42
    var y float64 = 42.5
    fmt.Println(float64(x) + y) // 84.5
    fmt.Println(x + int(y)) // 84

    var z string = "hank"
    fmt.Println([]byte(z)) //[104 97 110 107]

    var a []byte = []byte {104, 97, 110, 107,}
    fmt.Println(string(a)) // hank

除此之外的类型间的相互转换是不被允许,例如将其他类型转为布尔类型。

代码演示:

var b int = 0 
fmt.Println(bool(b))
// 报错: #command-line-arguments
// .\type.go:73:18: cannot convert b (type int) to type bool

7.类型定义

自定义的的数据类型。 可以基于内置的数据类型,构建自定义的数据类型,称之为类型定义。使用语法: type 类型标识符 类型描述字面量

最典型的情况,就是结构体类型的定义:

type Person struct {
   ID string
   Name string
   age int 
}

其中,Person 就是我们自定义的数据类型,其对应的类型描述,是后边的结构体类型 的字面量。

除了结构体,我们可以使用任意的内置类型来定义我们的自定义类型,演示:

// 类型定义
type age int
type height int
type position struct {
  x int
  y int 
}
type hobby []string

定义好的数据类型,使用的语法与内置的类型一致,演示:

type age int
var a age = 42
fmt.Println(a, a + 42) // 42 84

type hobby []string
var c hobby = hobby{"basketball", "football"} 
//亦可 :c := hobby{"basketball", "football"}

fmt.Println(c, len(c), c[1]) // [basketball football] 2 football

注意:基于某种类型定义的新类型,继承某种类型的方法集合(操作集合),age 就支持 int
型加减乘除运算,hobby 类型就支持 []string 的索引,长度等运算。但是,定义的类型与其基础类型(就是 age 和 int)是不同的两种数据类型,不能做直接运算,但是可以通过类型转换,转换为对应的类型。

var a age = 42
var b int = 1024
// fmt.Println(a, a + 42, a + b) 
// 报错 .\type.go:86:27: invalid operation: a + b (mismatched types age and int)

fmt.Println(a, a + 42, a + age(b), int(a) + b) 
// 输出:42 84 1066 1066

为了统一概念,任何数据类型都有基础类型,包括 int 和[]string,这些预定义的内置类 型或类型的字面量的基础类型是其本身。

其中,类型字面量包括自定义类型的字面量类型,例如,若:type ages []age,其中 ages 的基础类型就是 []age。

8.类型别名

别名,另一个名字,同一个类型的不同的名字,称之为类型别名。

语法:type 别名 = 类型 (与类型定义的差异是存在等号)

代码演示:

type age = int
var a age = 42
var b int = 1024 
fmt.Println(a, a + 42, a + b) // 42 84 1066

给类型取一个满足业务逻辑的名字,并没有增加新类型,因此不同别名但同一类型间的
数据,可以直接做运算!

内置的类型:
byte 和 rune 其实就是通过别名的方案来定义的,也是整型集团内的。

// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32

9.其他功能类型

功能上的类型,不表示数据,用于实现某个特定功能。有:

上一篇 下一篇

猜你喜欢

热点阅读