数据类型和表达式

2023-11-28 16:10:16 浏览数 (1)

数据类型和表达式

2019-04-07

11分钟阅读时长

当谈到Go的数据类型和表达式时,需要掌握以下这些知识:

  1. 基本数据类型:Go中的基本数据类型包括boolstringintint8int16int32int64uintuint8uint16uint32uint64uintptrbyterunefloat32float64。其中byteuint8的别名,runeint32的别名。

下面是关于Go基本数据类型的总结:

类型名称

类型描述

大小(字节)

默认值

范围

bool

布尔类型

1

false

true、false

byte

字节类型

1

0

0~255

rune

Unicode字符类型

4

0

-2147483648~2147483647

int

整数类型

平台相关

0

最大值和最小值取决于平台,通常为-2147483648~2147483647

int8

8位整数类型

1

0

-128~127

int16

16位整数类型

2

0

-32768~32767

int32

32位整数类型

4

0

-2147483648~2147483647

int64

64位整数类型

8

0

-9223372036854775808~9223372036854775807

uint

无符号整数类型

平台相关

0

最大值取决于平台,通常为0~4294967295

uint8

8位无符号整数类型

1

0

0~255

uint16

16位无符号整数类型

2

0

0~65535

uint32

32位无符号整数类型

4

0

0~4294967295

uint64

64位无符号整数类型

8

0

0~18446744073709551615

uintptr

指针类型

平台相关

0

保存指针地址的整数值

需要注意的是,Go语言中支持隐式类型转换,但是不同类型之间的转换需要满足特定的规则。另外,Go还提供了一种复合类型complex,用于表示复数。complex由实部和虚部两个float32float64类型组成,可以用于数学运算。

  1. 复合数据类型:Go中的复合数据类型包括数组、切片、映射、通道和结构体。

类型名称

类型描述

大小(字节)

初始化方式

数组(Array)

在内存中连续存储多个同类型元素的集合,长度固定不变

n * 元素大小

var a [n]T、a := [n]T{value1, value2, ..., valuen}、a := [...]T{value1, value2, ..., valuen}

切片(Slice)

动态数组,由指向底层数组的指针、长度和容量三部分组成

24

var s []T = make([]T, len, cap)、s := []T{value1, value2, ..., valuen}、s := make([]T, length)、s := make([]T, length, capacity)

映射(Map)

存储键值对的无序集合,每个键唯一对应一个值

平均8字节/条记录

var m map[T]U = make(map[T]U)、m := map[T]U{key1: value1, key2: value2, ..., keyn: valuen}

通道(Channel)

用于协程间通信的管道,支持发送和接收数据

0或者1

var ch chan T = make(chan T)、ch := make(chan T, buffer)

结构体 (Struct)

自定义类型,它由一系列不同类型的字段组成。结构体中的每个字段都有自己的标识符和类型。

N/A

type person struct {name stringage int}var p personp = person{name: "Alice", age: 30}

需要注意的是,Go 语言中除了数组和结构体外,其他数据类型都是引用类型。这意味着切片、映射等类型在传递给函数或赋值给变量时,实际上是传递了一个指向底层数据结构的指针。因此,在操作这些数据类型时需要小心避免出现副作用。

以下是一些关于Golang复合数据类型数组(Array)的一些例子
  1. 字符串数组
代码语言:javascript复制
var names [3]string
names[0] = "Alice"
names[1] = "Bob"
names[2] = "Charlie"
  1. 布尔数组
代码语言:javascript复制
var flags [4]bool
flags[0] = true
flags[1] = false
flags[2] = false
flags[3] = true
  1. 浮点数数组
代码语言:javascript复制
var prices [5]float64
prices[0] = 1.99
prices[1] = 2.99
prices[2] = 3.99
prices[3] = 4.99
prices[4] = 5.99
  1. 结构体数组
代码语言:javascript复制
type Person struct {
    Name string
    Age int
}

var people [2]Person
people[0] = Person{"Alice", 30}
people[1] = Person{"Bob", 25}
  1. 多维数组
代码语言:javascript复制
var matrix [3][3]int
matrix[0] = [3]int{1, 2, 3}
matrix[1] = [3]int{4, 5, 6}
matrix[2] = [3]int{7, 8, 9}
以下是一些关于Golang复合数据切片(Slice)类型的一些例子
代码语言:javascript复制
numbers := []int{1, 2, 3, 4, 5}

以上代码定义了一个名为 numbers 的整数类型切片,其中包含元素 1、2、3、4 和 5。可以通过下标访问切片中的元素。

还可以使用 make 函数来创建指定长度和容量的切片:

代码语言:javascript复制
numbers := make([]int, 5, 10)

该语句创建了一个长度为 5,容量为 10 的整数类型切片。此时所有元素默认初始化为0。

可以使用 append() 函数将元素添加到切片末尾:

代码语言:javascript复制
numbers = append(numbers, 6, 7, 8)

此时 numbers 切片的元素变成了 1、2、3、4、5、6、7 和 8。

还可以通过切片操作来获取子切片:

代码语言:javascript复制
subNumbers := numbers[2:5]

以上代码创建了一个从索引 2 开始,到索引 5 结束(不包括索引 5)的子切片。子切片 subNumbers 包含元素 3、4 和 5。

以下是一些关于Golang复合数据映射(Map)类型的一些例子
代码语言:javascript复制
ages := map[string]int{
    "Alice": 30,
    "Bob":   25,
    "Charlie": 35,
}

以上代码定义了一个名为 ages 的映射,其中键为字符串类型,值为整数类型。它包含三个条目,分别表示 Alice、Bob 和 Charlie 的年龄。

可以使用索引操作符 [] 获取映射中的值:

代码语言:javascript复制
fmt.Println(ages["Alice"]) // 输出:30

还可以使用 make() 函数创建空映射:

代码语言:javascript复制
scores := make(map[string]int)

该语句创建了一个名为 scores 的空映射,键为字符串类型,值为整数类型。

可以使用 delete() 函数从映射中删除条目:

代码语言:javascript复制
delete(ages, "Bob")

此时映射中不再包含键为 Bob 的条目。

以下是一些关于Golang复合数据通道(Channel)类型的一些例子
代码语言:javascript复制
package main

import "fmt"

func main() {
    // 创建一个整数类型的通道
    ch := make(chan int)

    // 使用 go 关键字启动一个新的 goroutine
    go func() {
        // 向通道发送值
        ch <- 42
    }()

    // 从通道接收值
    i := <-ch

    fmt.Println(i) // 输出:42
}

在这个例子中,我们创建了一个整型通道 ch,然后启动了一个新的 goroutine,在其中向通道发送了值 42。在主 goroutine 中我们从通道 ch 中接收该值,并将其打印到控制台上。

以下是另一个使用 Golang 中通道数据类型的示例:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 创建一个字符串类型的通道
    ch := make(chan string)

    // 使用 go 关键字启动一个新的 goroutine
    go func() {
        // 向通道发送三个不同的字符串
        ch <- "Hello"
        ch <- "world"
        ch <- "!"

        // 关闭通道
        close(ch)
    }()

    // 循环从通道接收值,直到通道被关闭
    for msg := range ch {
        fmt.Println(msg) // 输出:Hello world !
    }
}

在这个例子中,我们创建了一个字符串通道 ch,然后启动了一个新的 goroutine,在其中向通道发送了三个不同的字符串。在主 goroutine 中我们使用 range 语句循环从通道 ch 中接收每个字符串,并将它们打印到控制台上,直到通道被关闭为止。

这个例子展示了如何在多个 goroutine 之间安全地传递数据,以及如何在通道被关闭时停止接收数据。

以下是一些关于Golang复合数据结构体(Struct)类型的一些例子

以下是一些使用 Golang 结构体的例子:

代码语言:javascript复制
package main

import "fmt"

// 定义一个表示人的结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    // 创建一个新的 Person 对象
    p1 := Person{Name: "Alice", Age: 30}

    // 访问 Person 的属性
    fmt.Println(p1.Name) // 输出:Alice
    fmt.Println(p1.Age)  // 输出:30

    // 可以创建一个匿名结构体
    p2 := struct {
        Name string
        Age  int
    }{
        Name: "Bob",
        Age:  40,
    }

    // 访问匿名结构体的属性
    fmt.Println(p2.Name) // 输出:Bob
    fmt.Println(p2.Age)  // 输出:40

    // 可以将结构体作为函数参数和返回值
    p3 := createPerson("Charlie", 50)
    fmt.Println(p3) // 输出:{Charlie 50}
}

// 创建一个新的 Person 对象并返回
func createPerson(name string, age int) Person {
    return Person{
        Name: name,
        Age:  age,
    }
}

在这个示例中,我们定义了一个表示人的结构体 Person,包含两个属性 NameAge。然后我们创建了一个新的 Person 对象 p1,并访问了它的属性。

接着我们定义了一个匿名结构体 p2,也有 NameAge 属性,并访问了它的属性。

最后,我们定义了一个函数 createPerson,它接收两个参数 nameage,并返回一个新的 Person 对象。我们使用这个函数创建了一个新的 Person 对象 p3,并打印它的值。

除此之外,结构体还可以用于嵌套和组合,以及实现接口等高级应用。

  1. 类型转换:在Go中,当需要将一个类型的值转换为另一个类型时,需要使用类型转换操作符T(v),其中T表示目标类型,v表示要转换的值。需要注意的是,不是所有类型之间都可以进行转换,只有具有相同底层类型或者满足特定条件的类型之间才可以进行转换。

以下是一些使用 Golang 类型转换的例子:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 将整数类型转换为浮点数类型
    i := 42
    f := float64(i)
    fmt.Println(f) // 输出:42.0

    // 将浮点数类型转换为整数类型
    f = 3.14
    i = int(f)
    fmt.Println(i) // 输出:3

    // 将字符串类型转换为整数类型
    s := "42"
    i, err := strconv.Atoi(s)
    if err != nil {
        panic(err)
    }
    fmt.Println(i) // 输出:42

    // 将整数类型转换为字符串类型
    s = strconv.Itoa(i)
    fmt.Println(s) // 输出:42

    // 将接口类型转换为具体类型
    var v1 interface{} = "Hello, world!"
    s, ok := v1.(string)
    if ok {
        fmt.Println(s) // 输出:"Hello, world!"
    }

    // 将指针类型转换为具体类型
    var v2 interface{} = &Person{Name: "Alice", Age: 30}
    p, ok := v2.(*Person)
    if ok {
        fmt.Println(p.Name, p.Age) // 输出:"Alice 30"
    }
}

// 定义一个表示人的结构体
type Person struct {
    Name string
    Age  int
}

在这个示例中,我们首先展示了如何将整数类型转换为浮点数类型,以及如何将浮点数类型转换为整数类型。

接着我们展示了如何将字符串类型转换为整数类型,并使用 strconv 包中的 Atoi 函数实现了该操作。我们还展示了如何将整数类型转换为字符串类型,并使用 strconv 包中的 Itoa 函数实现了该操作。

然后,我们演示了如何将接口类型转换为具体类型,并使用类型断言实现了该操作。我们还展示了如何将指针类型转换为具体类型,并使用类型断言实现了该操作。

需要注意的是,在类型转换过程中可能会发生类型不匹配或溢出等问题,因此需要谨慎处理。

  1. 表达式:Go中的表达式由运算符和操作数组成,可以分为算术表达式、比较表达式、逻辑表达式、位运算表达式、赋值表达式等多种类型。

以下是一些使用 Golang 表达式的例子:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 算术表达式
    a := 1   2*3/4
    fmt.Println(a) // 输出:2

    // 比较表达式
    b := (a == 2)
    fmt.Println(b) // 输出:true

    // 逻辑表达式
    c := !(b && true) || false
    fmt.Println(c) // 输出:false

    // 位运算表达式
    d := 0b1100 & 0b1010
    fmt.Printf("bn", d) // 输出:1000

    // 赋值表达式
    e := 42
    e  = 8
    fmt.Println(e) // 输出:50

    // 条件表达式
    f := true
    g := func() int {
        if f {
            return 42
        } else {
            return 0
        }
    }()
    fmt.Println(g) // 输出:42
}

在这个示例中,我们首先展示了如何使用算术表达式,包括加减乘除和求余等操作。

接着我们展示了如何使用比较表达式,包括相等、不等、大于、小于等操作。我们还展示了如何使用逻辑表达式,包括与、或、非等操作。

然后我们演示了如何使用位运算表达式,包括按位与、按位或、异或等操作。需要注意的是,在 Golang 中需要使用前缀 0b 表示二进制数值。

接下来我们展示了如何使用赋值表达式,包括加、减、乘、除等操作。可以看到在这里我们使用了 = 运算符实现了加法操作。

最后我们演示了如何使用条件表达式,包括 if 语句和函数调用等操作。在这个示例中,我们定义了一个匿名函数,并使用它返回不同的值,根据变量 f 的值来决定返回什么。

  1. 运算符优先级:在Go中,每个运算符都有自己的优先级,当多个运算符同时出现在一个表达式中时,按照优先级从高到低依次计算。需要注意的是,优先级相同的运算符会按照从左到右的顺序依次计算。

以下是一些使用 Golang 运算符优先级的例子:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 后置    运算符的优先级最高
    a := 1
    b := a  
    fmt.Println(b) // 输出:1

    // * 和 / 运算符的优先级高于   和 -
    c := 1   2*3/4
    fmt.Println(c) // 输出:2

    // < 和 > 运算符的优先级低于 == 和 !=
    d := (c != 2 && c < 3)
    fmt.Println(d) // 输出:false

    // && 运算符的优先级低于 ||
    e := false || true && true
    fmt.Println(e) // 输出:true

    // 赋值运算符的优先级低于大部分运算符
    f := 1   2
    f *= 3   4
    fmt.Println(f) // 输出:21
}

在这个示例中,我们首先展示了后置 运算符的优先级最高,即在其他表达式执行完毕后对变量进行自增操作。

接着我们展示了乘法和除法运算符的优先级高于加法和减法运算符。

然后我们演示了比较运算符的优先级低于相等和不等运算符。需要注意的是,在 Golang 中相等和不等运算符是 ==!= 而不是 =<>

接下来我们展示了逻辑运算符的优先级,包括 &&||。需要注意的是,在 Golang 中逻辑运算符也是短路运算符。

最后我们演示了赋值运算符的优先级低于大部分其他运算符,包括加法和乘法运算符。可以看到在这里我们使用了 *= 运算符实现了乘法操作。

  1. 类型断言:在Go中,可以通过类型断言操作符x.(T)将一个接口类型的值转换为具体类型的值,其中x表示要转换的值,T表示目标类型。如果转换成功,返回转换后的值和一个布尔值true;否则返回零值和一个布尔值false

以下是一些使用 Golang 类型断言的例子:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 将接口类型转换为具体类型
    var v1 interface{} = "Hello, world!"
    s, ok := v1.(string)
    if ok {
        fmt.Println(s) // 输出:"Hello, world!"
    }

    // 将指针类型转换为具体类型
    var v2 interface{} = &Person{Name: "Alice", Age: 30}
    p, ok := v2.(*Person)
    if ok {
        fmt.Println(p.Name, p.Age) // 输出:"Alice 30"
    }

    // 在 switch 语句中使用类型断言
    var v3 interface{} = 42
    switch v := v3.(type) {
    case int:
        fmt.Println("v is an integer:", v)
    case float64:
        fmt.Println("v is a float64:", v)
    default:
        fmt.Println("v is of a different type")
    }
}

// 定义一个表示人的结构体
type Person struct {
    Name string
    Age  int
}

在这个示例中,我们首先演示了如何将接口类型转换为具体类型,并使用类型断言实现了该操作。我们定义了一个接口类型变量 v1,并尝试将其转换为字符串类型。

接着我们展示了如何将指针类型转换为具体类型,并使用类型断言实现了该操作。我们定义了一个接口类型变量 v2,并尝试将其转换为 Person 结构体类型。

然后我们演示了如何在 switch 语句中使用类型断言。我们定义了一个接口类型变量 v3,并在 switch 语句中尝试将其转换为不同的类型。

需要注意的是,在进行类型断言时,如果类型不匹配会返回 false 和默认值,因此需要谨慎处理。

  1. 指针:指针是一种特殊类型的变量,存储了内存地址。在Go中,使用&操作符获取变量的地址,使用*操作符获取指针所指向的变量的值。指针可以用于传递函数参数、处理数据结构等方面。

以下是一些使用 Golang 指针的例子:

代码语言:javascript复制
package main

import "fmt"

func main() {
    // 定义一个指针变量并赋值
    var p1 *int
    x := 42
    p1 = &x
    fmt.Println(*p1) // 输出:42

    // 使用 new 函数创建指针对象
    p2 := new(int)
    *p2 = 100
    fmt.Println(*p2) // 输出:100

    // 函数中使用指针参数
    y := 42
    increment(&y)
    fmt.Println(y) // 输出:43
}

// 将指定变量的值加 1
func increment(p *int) {
    *p  
}

在这个示例中,我们首先展示了如何定义一个指针变量并赋值。我们通过 & 运算符获取变量 x 的地址,并将其赋值给指针变量 p1。然后我们使用 * 运算符访问指针所指向的变量的值,并打印出来。

接着我们演示了如何使用 new 函数创建指针对象。我们使用 new 函数创建了一个新的整数类型变量,并将其地址赋值给指针变量 p2。然后我们使用 * 运算符访问指针所指向的变量的值,并打印出来。

最后,我们演示了如何在函数中使用指针参数。我们定义了一个 increment 函数,并接收一个指针类型参数 p。函数会将 p 指向的变量的值加 1。在调用函数时,我们传递了变量 y 的地址作为参数,并将其值加 1。最后我们打印出变量 y 的值,可以看到它已经被成功地增加了 1。

0 人点赞