zoukankan      html  css  js  c++  java
  • Go从入门到精通——数据类型

    Go 数据类型

    本章介绍如下内容: 

    • 数据类型是什么?
    • 区分静态类型和动态类型
    • 使用布尔类型
    • 理解数值类型
    • 检查变量的类型
    • 类型转换

      Go 是一种静态类型语言,而静态类型是一个必须理解的概念。如果您没有接触过静态类型语言,这个概念的理解尤为重要。

    1.1 数据类型是什么

      数据类型让编程语言、编译器、数据库和代码执行环境知道如何操作和处理数据。例如,如果数据类型为数字,通常可对其执行数学运算。编程语言和数据库常常根据数据类型赋予程序员不同的功能和性能。大多数编程语言还提供了用于处理常见数据的标准库,而数据库提供了查询语言,让程序员能够根据底层数据类型来查询数据以及与之交互。无论数据类型是否被显示地声明,它们都是重要的编程和计算结构。

    1.2 区分静态类型和动态类型

      所谓强类型语言,指的是错误地使用了类型时,编译器将引发错误;所谓动态类型(也叫松散类型或弱类型)语言,指的是为了执行程序,运行时会将一种类型转换为另一种类型,或者编译器没有实现类型系统。哪种语言更好呢?这存在很大争议,计算机科学家看重强类型语言的正确性和安全性,而其他人则看重动态语言的简单性和开发速度。

      下面是静态类型语言的一些优点:

    • 性能高于动态类型语言。
    • Bug 通常会被编译器发现。
    • 代码编辑器可提供代码不全和其他功能。
    • 数据完整性更好。

      下面是动态类型语言的一些优点:

    • 使用动态类型语言编写软件的速度通常更快。
    • 无须为执行代码而等待编译器完成编译。
    • 动态类型语言通常不那么死板,因此有些人认为变更代码更容易。
    • 有些人认为动态类型语言门槛更低。

      在 Go 中,程序员可显示地声明类型,也可让编译器推断类型。这里我们将显示地声明类型:

      从sayHello函数的参数声明可知,这个函数接受一个类型为 string 的参数;这个函数的返回值也是字符串。因此,编译这个程序时,编译器将检查传递给这个函数的参数是否是字符串;如果不是,编译器将发生错误。这正是我们希望的,因为这意味着错误可能根本不会让用户遇到。 

      Python 也是强类型语言,我们再看看 Python 的函数,它接受两个值,将它们相加并返回结果:

    >>> def func(a,b):
    ...     return a + b;
    ... 
    

      给这个函数提供两个数字时,它能够正确地运行:

      然而,如果向它传递一个数字和一个字符串呢?

     

      我们再尝试弱类型语言 Javascript 函数,它也接受两个值,将它们相加并返回结果。

    var addition = function(a,b) {
        return a,b;
    };

      如 python 函数一样,我们这里也给这个函提供两个数字时,看看它能够正确地运行吗?

      给这个 Javasscript 函数提供两个数字数值的参数时候,是能够正常地运行的。现在我们再向它传递一个数字和一个字符串,看看结果如何:

      可以看的到, 执行 Javascript 函数后,虽然也可以的到结果,但是结果很奇怪。

      在这种情况下,这个函数返回一个字符串。怎么会这样呢?虽然 JavaScript 有类型的概念,但其类型使用规则非常宽松。在这个示例中,Javascript 对数字值执行类型转换,将其转换为字符串,因此返回字符串 7eight。Javascript 提供的这种灵活性虽然很有吸引力,但可能导致微妙乃至灾难性的 Bug。

      上述的 Javascript 函数 myFunction 函数可能返回一个字符串,也可能返回一个整数。如果传递给它的值至少有一个字符串,返回的就是字符串。如果这个返回值被插入到需要整数的数据库字段中,将引发错误。更糟糕的是,这种错误发生在运行阶段,这意味着它将影响使用程序的用户。这种错误除非得到妥善处理,否则可能导致程序崩溃。

      而在使用 Go 语言编写的函数中,对参数和返回值的类型都做了声明。

      下面我们也运行下 Go 语言的情况,如 Python 函数一样,我们这里也给这个函提供两个数字时,看看它能够正确地运行吗?

      结果是可以正确地运行。如果我们传入字符串试试呢?

     

      尝试运行程序后,发生了报错。报错信息为:".int+int.go:14:28: cannot use "8" (type untyped string) as type int in argument to myFunction",原因是因为在需要 int 类型的地方使用了字符串。

    1.3 使用布尔类型

      对类型有了基本认识后,就可以探索 Go 是如何实现一些基本数据类型了。首先来看布尔类型。布尔值只能为 true 或 false。虽然有些语言允许使用值 1 和 0 来表示 true 和 false,但 Go 语言不允许。可像下面这样声明布尔变量:

    var a bool

      如果没有给布尔变量赋值,它将默认为 false:

      布尔变量可在声明后重新赋值,它们是很有用的编程元素:

     1.4 理解数值类型

      对编程来说,数值不可或缺。然而,如果您没有计算机科学或数学方面的知识,可能对有些术语感到迷惑。您可能听说过浮点数、整数、无符号整数、8位、64位、bigint、smallint、tinyint,这些都是整型(数值)类型。要明白这些术语的含义,必须知道数字在计算机内部是以二进制位的方式存储的。二进制位就是一些列布尔值,取值要么为1,要么为0。1位可表示1或0,对于4位整数,下面对其二进制位和十进制位表示做了比较。从该表可知,4位可表示16个不同的数字:

    4位的无符号整数

    二进制 十进制
    0000 0
    0001 1
    0010 2
    0011 3
    0100 4
    0101 5
    0110 6
    二进制 十进制
    0111 7
    1000 8
    1001 9
    1010 10
    1011 11
    1100 12
    1101 13
    二进制 十进制
    1110 14
    1111 15

    1.4.1 带符号整数和无符号整数

      对于带符号整数,需要使用一位来表示符号,这通常是符号 - 。上表列出了无符号的 4 位整数,其取值范围为 0~15。带符号整数可正可负,因此 4 位带符号整数的取值范围为 -8 到 7。

    4位的无符号整数

    二进制 十进制
    0000 0
    0001 1
    0010 2
    0011 3
    0100 4
    0101 5
    0110 6
    二进制 十进制
    0111 7
    1000 -8
    1001 -7
    1010 -6
    1011 -5
    1100 -4
    1101 -3
    二进制 十进制
    1110 -2
    1111 -1

     

      在 Go 语言中,声明整型变量的方式如下:

    var  i int =3

      类型 int 表示带符号整数,因此可正科负。根据计算机的底层体系结构,int 可能是 32 位的带符号整数,也可能是 64 位的带符号整数。除非要处理的数字非常大,或者非常在乎性能,否则只需要使用 int,而无须关心编译器是如何做的。

    1.4.2 浮点数

      计算语言中将数学中的小数称作浮点数,这是由小数在计算机中的表达形式而产生的叫法(通过小数点的浮动来表示更大范围小数)。

      在 Go 语言中常用的浮点数有两种:float32 和float64。其中,float32 类型的浮点数由 32 个二进制位组成的,而 float64 则是由 64 个二进制位组成的。显而易见,float64 类型的浮点数可以表达的数字范围更大或者精度更高。在实际应用中,我们可以自行选择使用 float32 还是 float64 作为变量类型,唯一需要考虑的是 Go 语言标准库或第三方库中的函数要求使用哪种类型。

      目前,Go 语言标准库中大多数涉及浮点数计算的函数已经以使用 float64 参数为主,因此,建议定义变量类型时使用 float64 类型。

    1.4.3 字符串

      字符串可以是任何字符序列,其中的字符可能是数字、字母和字符。下面是一些简单的字符串:

    • cow
    • $%^&*
    • a1234

      几乎所有的编程语言都支持字符串,它们通常包含数字、字母或符号。在 Go 语言中,声明并初始化字符串变量很简单。

    var a string = 'foo'
    

      字符串变量可以为空,这种变量非常适合用来积累其他变量中的数据以及存储临时数据。

    var  s string = ""
    

      创建字符串变量后,可将其与其他数据相加,但不能修改原来的值。下面的代码创建个空字符串,再将字符串 foo 附加到末尾,这在 Go 语言中是合法的。

    var s  sting = ""
    s += "foo"
    

      不能对字符串执行数学运算,即便它看起来像个数字。要看对看起来像数字的字符串执行数学运算,必须先将其转换为数字类型。

    1.4.4 数组

      数组是几乎所有编程语言都支持的另一种数据类型,这是一种比较复杂的类型,因为它包含一系列元素。例如,要表示乐队的成员,使用字符串数组是不错的选择。声明数组时,必须制定其长度和类型。

    var beatles [4]string
    

      在这个示例中,方括号内的数字表示数组的长度,而紧跟在方括号后的是数组的类型,这里为字符串:

    beatles[0] = "John"
    beatles[1] = "Paul"
    beatles[2] = "Ringo"
    beatles[3] = "George"
    

      数组索引是从 0 开始。在上述变量声明中,指定的数组长度为 4,但访问这个数组的元素时,索引最大为 3.这是因为在所有数组中,索引都从 0 开始。

    1.5 检查变量的类型

      有些情况下,需要检查变量的类型,为此可使用标准库中 reflect 包,它让您能够访问变量的底层类型。在大多数情况下,编译器能发现类型不正确的情形,但在调试或必须核实底层类型时,reflect 包将很有用。

    程序:使用 reflect 包检查变量类型


    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    	var s string = "string"
    	var i int = 10
    	var f float32 = 1.2
    
    	fmt.Println(reflect.TypeOf(s))
    	fmt.Println(reflect.TypeOf(i))
    	fmt.Println(reflect.TypeOf(f))
    
    }
    

     1.6 类型转换

      将数据从一种类型转换为另一种类型是常见的编程任务,这通常是在从网络或数据库读取数据进行的。Go 标准库提供了良好的类型转换支持。

    valueOfTypeB = typeB(valueOfTypeA)

      简单的转换操作:

    // 浮点
    a := 5.0
    
    //转换为 int 类型
    b := int(a)
    

      Go允许在底层结构相同的两个类型之间互转。例如:

    // blue 类型的底层是 int 类型
    type blue int
    
    // a的类型为 blue,底层是 int
    var a blue = 5
    
    // 将a(blue)转换为 int,b现在是 int 类型
    b := int(5)
    
    // 将b(int)转换为 blue,c现在是 blue 类型
    c := blue(b)
    
    • 不是所有数据类型都能转换的,例如字母格式的string类型"abcd"转换为int肯定会失败
    • 低精度转换为高精度时是安全的,高精度的值转换为低精度时会丢失精度。例如int32转换为int16,float32转换为int
    • 这种简单的转换方式不能对int(float)和string进行互转,要跨大类型转换,可以使用strconv包提供的函数

    strconv 包提供了一整套类型转换方法,可用于转换为字符串或字符串转换为其他类型。这个包里提供了很多函数,大概分为几类:

    • 字符串转int:Atoi()
    • int转字符串: Itoa()
    • ParseTP类函数将string转换为TP类型:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。因为string转其它类型可能会失败,所以这些函数都有第二个返回值表示是否转换成功
    • FormatTP类函数将其它类型转string:FormatBool()、FormatFloat()、FormatInt()、FormatUint()
    • AppendTP类函数用于将TP转换成字符串后append到一个slice中:AppendBool()、AppendFloat()、AppendInt()、AppendUint()

    1.6.1 strconv:string 和 int 转换

      最常见的是字符串和 int 之间的转换。

      1、 int 转换为字符串:Itoa()

    // Itoa(): int -> string
    println("a" + strconv,Itoa(32))  //a32
    

      2、string 转换为 int:Atoi()

    func Atoi(s string) (int, error)
    

      由于string可能无法转换为int,所以这个函数有两个返回值:第一个返回值是转换成int的值,第二个返回值判断是否转换成功。

    // Atoi(): string -> int
    i,_ := strconv.Atoi("3")
    println(3 + i)   // 6
    
    // Atoi()转换失败
    i,err := strconv.Atoi("a")
    if err != nil {
        println("converted failed")
    }
    

    1.6.2 strconv:Parse类函数

      Parse类函数用于转换字符串为给定类型的值:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。

      由于字符串转换为其它类型可能会失败,所以这些函数都有两个返回值,第一个返回值保存转换后的值,第二个返回值判断是否转换成功。

    b, err := strconv.ParseBool("true")
    f, err := strconv.ParseFloat("3.1415", 64)
    i, err := strconv.ParseInt("-42", 10, 64)
    u, err := strconv.ParseUint("42", 10, 64)
    

      ParseFloat()只能接收float64类型的浮点数。

      ParseInt()和ParseUint()有3个参数:

    func ParseInt(s string, base int, bitSize int) (i int64, err error)
    func ParseUint(s string, base int, bitSize int) (uint64, error)
    

    1.6.3 strconv:Format类函数

      将给定类型格式化为string类型:FormatBool()、FormatFloat()、FormatInt()、FormatUint()。

    //FormatInt()和FormatUint()有两个参数:
    func FormatInt(i int64, base int) string
    func FormatUint(i uint64, base int) string

    1.6.4 strconv:Append类函数

      AppendTP类函数用于将TP转换成字符串后append到一个slice中:AppendBool()、AppendFloat()、AppendInt()、AppendUint()。
      Append类的函数和Format类的函数工作方式类似,只不过是将转换后的结果追加到一个slice中。

  • 相关阅读:
    Cisco网络模拟器踩坑记录
    PAT甲级1009水题飘过
    PAT甲级1011水题飘过
    springmvc中项目启动直接调用方法
    Eclipse中Java文件图标由实心J变成空心J的问题
    mysql求时间差
    maven常用命令
    java单例模式(两种常用模式)
    mybatis一对多,多对一
    mybatis简介
  • 原文地址:https://www.cnblogs.com/zuoyang/p/15119343.html
Copyright © 2011-2022 走看看