Go基础|第3章:基本类型、变量与常量

  • 原创
  • Madman
  • /
  • /
  • 0
  • 1304 次阅读

Golang.jpg

Synopsis: Go 语言将数据类型分为四类:基本类型、复合类型、引用类型和接口类型,本文仅简单介绍下布尔型、字符串、整型、浮点型、复数等基本类型,各类型的详细说明可以参考《The Go Programming Language》,然后学习如何声明变量和常量

1. 基本类型

Go 的基本类型有三类:

  1. 布尔型 bool: 只有 truefalse 两种值,支持以下逻辑运算符
    • &&
    • ||
    • !
  2. 字符串 string: 是一个不可改变的字节序列,文本字符串通常被解释为采用 UTF8 编码的 Unicode code point(rune)序列。注意: 内置的 len() 函数返回一个字符串中的字节数目(不是 rune 字符数目)
  3. 数值型
    • 整数 int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/uintptr/byte/rune
    • 浮点数 float32/float64
    • 复数 complex64/complex128

其中 byteuint8 的别名。runeint32 的别名,表示一个 Unicode code point(比如字符 𪸿 的 Unicode 码点为 U+2AE3F,十六进制转换为十进制后的整数为 175679):

// 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  // Go 1.9 开始用户也可以声明自定义的类型别名(type alias)

// 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

注意: 字符串必须用双引号,比如 "hello"。单引号表示一个 rune 字符,比如 '𪸿'

2. 变量

使用 var 关键字来声明一个或多个变量,注意类型在变量名之后

package main

import "fmt"

// 包级别声明的变量会在 main 入口函数执行前完成初始化
var a int = 10

func main() {
  fmt.Printf("%T %v\n", a, a)

  // 局部变量将在声明语句被执行到的时候完成初始化
  var b int = 20
  fmt.Printf("%T %v\n", b, b)

  // 可以在一个声明语句中同时声明一组变量(变量类型相同),保留最后的类型即可
  var c, d bool = true, false
  fmt.Printf("%T %v\n", c, c)
  fmt.Printf("%T %v\n", d, d)

  var e string = "hello"
  var f float32 = 3.14
  fmt.Printf("%T %v\n", e, e)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
int 10
int 20
bool true
bool false
string hello
float32 3.14
*/

使用小括号 分组 形式声明多个变量:

var (
  b bool    = true
  s string  = "hello"
  i int     = 10
  f float64 = 3.14
)

一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化:

var f, err = os.Open(name)  // os.Open returns a file and an error  表达式在运行时(run time)被计算

2.1 零值

声明变量时,这个变量对应的值总是会被初始化。要么用指定的值初始化,要么用变量类型的默认值 零值(zero value) 做初始化

  • 布尔型: false
  • 字符串: ""(空字符串)
  • 数值型: 0
package main

import "fmt"

func main() {
  var b bool
  var s string
  var i int
  var f float64
  fmt.Printf("%v %q %v %v\n", b, s, i, f)
}

/* Output:
false "" 0 0
*/

其它零值:

  • 引用类型(function、slice、map、channel、pointer和interface)对应的零值是 nil
  • array 或 struct 等聚合类型对应的零值是每个元素或字段所对应的类型的零值

零值初始化机制可以确保每个声明的变量总是有一个良好定义的值,因此在 Go 语言中不存在未初始化的变量。这个特性可以简化很多代码,而且可以在没有增加额外工作的前提下确保边界条件下的合理行为

2.2 类型推导

在声明一个变量而不指定其类型时,变量的类型由右值推导得出

package main

import "fmt"

func main() {
  var b, s, i, f = false, "hello", 10, 3.14
  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/

当右值声明了类型时,新变量的类型与其相同:

var i int
j := i  // j 也是一个 int

2.3 短变量声明

函数(比如 func main() {...})中,如果右值的类型明确,可以用 := 代替 var 声明变量。短变量声明 := 在一次操作中完成两件事情:声明一个变量、并初始化

函数外的每个语句都必须以关键字开始(比如 importvar 等),因此 := 只能在函数内使用

package main

import "fmt"

// var 声明变量可以出现在函数外
var b bool = false

// b := false  // 报错: syntax error: non-declaration statement outside function body

func main() {
  // var 声明变量也可以出现在函数内
  var s = "hello"

  // 短变量声明 := 只能出现在函数内
  i, f := 10, 3.14
  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/

注意: := 是一个变量声明语句,而 = 是一个变量赋值操作

和普通 var 形式的变量声明语句一样,短变量声明语句也可以用函数的返回值来声明和初始化变量:

// 注意: f 和 err 至少有一个变量之前未被声明过,或者会报错 compile error: no new variables,此时只能使用 = 赋值操作
f, err := os.Open(name)
defer f.Close()

if err != nil {
  return err
}

要特别注意短变量声明语句的作用域范围:

package main

import (
  "fmt"
  "log"
  "os"
)

var cwd string

func init() {
  cwd, err := os.Getwd() // 不同代码块中的重名变量 cwd
  if err != nil {
    log.Fatalf("os.Getwd failed: %v", err)
  }
  // 如果注释掉下面的语句编译不通过,因为内部重声明的 cwd 变量未使用
  // compile error: cwd declared and not used
  fmt.Printf("Working directory = %s \n", cwd)
}

func main() {
  fmt.Printf("%T %q\n", cwd, cwd)
}

/* Output:
Working directory = D:\MyCode\go-in-action
string ""
*/

虽然 cwd 在外部已经声明过,但是 := 语句声明的 cwd 和 err 是新的局部变量,与外部的 cwd 属于不同的代码块,所以可以重名(不同代码块中的重名变量)。而 变量重声明 是在同一个代码块内,且只用于 := 语句中,比如:

func foo() {
  var err error
  n, err := io.WriteString(os.Stdout, "Hello, everyone!\n") // err 为变量重声明
  ...
}

因为内部声明的 cwd 将 屏蔽 外部的声明,所以上面的代码并不会正确更新包级声明的 cwd 变量值。为了避免出现类似潜在的问题,最直接的方法是通过单独声明 err 变量,来避免使用 := 简短声明方式:

package main

import (
  "fmt"
  "log"
  "os"
)

var cwd string

func init() {
  var err error
  cwd, err = os.Getwd()  // 不使用 :=
  if err != nil {
    log.Fatalf("os.Getwd failed: %v", err)
  }
  // 如果注释掉下面的语句,compile error: cwd declared and not used
  fmt.Printf("Working directory = %s \n", cwd)
}

func main() {
  fmt.Printf("%T %q\n", cwd, cwd)
}

/* Output:
Working directory = D:\MyCode\go-in-action
string "D:\\MyCode\\go-in-action"
*/

2.4 类型转换

表达式 T(v) 的意思是,将值 v 的类型转换为 T 类型,如果两个类型之间无法转换时,将报错: cannot convert v (type a) to type b

package main

import "fmt"

func main() {
  // var i int = 42
  i := 42
  fmt.Printf("%T %v\n", i, i)

  // var f float64 = float64(i)
  f := float64(i)
  fmt.Printf("%T %v\n", f, f)
}

/* Output:
int 42
float64 42
*/

3. 常量

常量的声明与变量类似,只不过是使用 const 关键字,常量可以被赋值为布尔值、字符/字符串、数值

使用小括号 分组 形式声明多个常量:

const (
  b bool    = true
  s string  = "hello"
  i int     = 10
  f float64 = 3.14
)

注意: 不能使用 := 语法声明常量

package main

import "fmt"

// const 声明常量可以出现在函数外
const b bool = false

func main() {
  // const 声明常量也可以出现在函数内
  const s = "hello"

  // const i  // 报错: missing value in const declaration,常量必须被明确赋值,没有零值的概念
  // const i, f := 10, 3.14  // 报错: syntax error: unexpected :=, expecting =

  // 类型推导
  const i, f = 10, 3.14

  fmt.Printf("%T %v\n", b, b)
  fmt.Printf("%T %v\n", s, s)
  fmt.Printf("%T %v\n", i, i)
  fmt.Printf("%T %v\n", f, f)

  // i = 20  // 报错: cannot assign to i,常量不可变
}

/* Output:
bool false
string hello
int 10
float64 3.14
*/
分类: Go Basic
标签: := bool const int string var
未经允许不得转载: LIFE & SHARE - 王颜公子 » Go基础|第3章:基本类型、变量与常量

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.