Go语言基本语法1.变量与常量2.基本类型介绍

搭建完Go的开发环境之后,我们就能开始愉快的编程了。

接下来就学习Go语言的类型有那些,他如何定义变量,常量。

1. 变量与常量

1.1 变量声明

Go 是静态类型语⾔,不能在运⾏期改变变量类型。

使⽤关键字 var 定义变量,每个变量会被初始化成其类型的默认值,例如: 整型和浮点型变量的默认值为0。 字符串变量的默认值为空字符串。 布尔型变量默认为false。 切片、函数、指针变量的默认为nil

  // 标准声明
  var number int
  var str string
  var isOk bool

  fmt.Println(number)
  fmt.Println(str)
  fmt.Println(isOk)

  fmt.Println("====================")

  // 批量声明
  var (
    number1 int
    str1    string
    isOk1   bool
  )

  fmt.Println(number1)
  fmt.Println(str1)
  fmt.Println(isOk1)
复制代码

结果如下:

image.png

1.2 变量初始化

变量的初始化有很多种方式,标准的是这样: var 变量名 类型 = 表达式

  var str2 string = "string"
  var number2 int = 1

  // 或者这样,一次性初始化多个变量
  var str3, number3 = "string", 2
复制代码

类型推导

将变量的类型省略,编译器会根据等号右边的值来推导变量的类型完成初始化。

  var str4 = "string"
  var number4 = 4
  
  // 打印结果
  //   4
  // string
复制代码

短变量声明

在函数内部,可以使用更简略的 := 方式声明并初始化变量。

package main

import (
  "fmt"
)

// 全局变量m

var m = 100

func main() {
  n := 10
  m := 200 // 此处声明局部变量m
  fmt.Println(m, n)

}
复制代码

匿名变量

在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示,例如:

package main

import (
  "fmt"
)

func main() {
  number5, _ := test()
  _, str5 := test()

  fmt.Println(number5)
  fmt.Println(str5)

}

func test() (int, string) {
  return 20, "string"
}
复制代码

匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明。

1.3 常量

常量定义

相对于变量,常量是恒定不变的值,多用于定义程序运行期间不会改变的那些值。 常量的声明和变量声明非常类似,只是把var换成了const,常量在定义的时候必须赋值

const PI = 3.14
const OTHER = "other"

const (
  PIL    = 3.14
  OTHERL = "other"
)
复制代码

同时声明多个常量,如果省略了值则和上一行的值相同

const (
  A = "A"
  B
  C
  D = "D"
  E
)
println(A, B, C, D, E) // A A A D D
复制代码

1.4 iota

iotago语言的常量计数器,只能在常量的表达式中使用。 iotaconst关键字出现时将被重置为0const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用。

  const (
    F = iota
    G
    H
    I
    J
  )
  println(F, G, H, I, J) //0 1 2 3 4
复制代码

使用_跳过某些值

const (
  n1 = iota //0
  n2        //1
  _
  n4        //3
)
复制代码

iota声明中间插队

const (
  n1 = iota //0
  n2 = 100  //100
  n3 = iota //2
  n4        //3
)

const n5 = iota //0
复制代码

定义数量级 (这里的<<表示左移操作,1<<10表示将1的二进制表示向左移10位,也就是由1变成了10000000000,也就是十进制的1024。同理2<<2表示将2的二进制表示向左移2位,也就是由10变成了1000,也就是十进制的8。)

const (
  _  = iota
  KB = 1 << (10 * iota)
  MB = 1 << (10 * iota)
  GB = 1 << (10 * iota)
  TB = 1 << (10 * iota)
  PB = 1 << (10 * iota)
)
复制代码

多个iota定义在一行

const (
  a, b = iota + 1, iota + 2 //1,2
  c, d                      //2,3
  e, f                      //3,4
)
复制代码

2. 基本类型介绍

Golang 更明确的数字类型命名,支持 Unicode,支持常用数据结构。

类型 长度(字节) 默认值 说明
bool 1 false
byte 1 0 uint8
rune 4 0 Unicode Code Point, int32
int, uint 4或8 0 32 或 64 位
int8, uint8 1 0 -128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32, uint32 4 0 -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint64 8 0
float32 4 0.0
float64 8 0.0
complex64 8
complex128 16
uintptr 4或8 以存储指针的 uint32 或 uint64 整数
array 值类型
struct 值类型
string "" UTF-8 字符串
slice nil 引用类型
map nil 引用类型
channel nil 引用类型
interface nil 接口
function nil 函数

支持八进制、 六进制,以及科学记数法。标准库 math 定义了各数字类型取值范围。

a, b, c, d := 071, 0x1F, 1e9, math.MinInt16

空指针值 nil,而非C/C++ NULL。

2.1 整型

整型分为以下两个大类: 按长度分为:int8int16int32int64对应的无符号整型:uint8uint16uint32uint64

其中,uint8就是我们熟知的byte型,int16对应C语言中的short型,int64对应C语言中的long型。

挺好奇go语言的int位数是多少:

import (
  "fmt"
  "runtime"
  "strconv"
)

func main() {
  fmt.Println("cpu型号:", runtime.GOARCH)
  fmt.Println("int位数:", strconv.IntSize)
}
复制代码

然后运行结果如下:

image_1.png

64位操作系统int位数是64。

2.2 浮点型

Go语言支持两种浮点型数:float32float64。这两种浮点型数据格式遵循IEEE 754标准: float32 的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

2.3 复数

complex64complex128

复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位。

2.4 布尔值

Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true(真)false(假)两个值。注意:

  • 布尔类型变量的默认值为false。
  • Go 语言中不允许将整型强制转换为布尔型.
  • 布尔型无法参与数值运算,也无法与其他类型进行转换。

2.5 字符串

Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号(")中的内容,可以在Go语言的源码中直接添加非ASCII码字符,例如:

s1 := "hello"
s2 := "你好"
复制代码

2.6 多行字符串

Go语言中要定义一个多行字符串时,就必须使用反引号字符:

s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
复制代码

反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。

2.7 字符串转义符

Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。

转义 含义
\r 回车符(返回行首)
\n 换行符(直接跳到下一行的同列位置)
\t 制表符
' 单引号
" 双引号
反斜杠

举个例子,我们要打印一个Windows平台下的一个文件路径:

package main

import (
  "fmt"
)

func main() {
  fmt.Println("str := "c:\pprof\main.exe"")
}
复制代码

2.8 字符串的常用操作

方法 介绍
len(str) 求长度
+或fmt.Sprintf 拼接字符串
strings.Split 分割
strings.Contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Index(),strings.LastIndex() 子串出现的位置
strings.Join(a[]string, sep string) join操作

2.9 byte和rune类型

组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(')包裹起来,如:

var a := '中'
var b := 'x'
复制代码

Go 语言的字符有以下两种:

  • uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
  • rune类型,代表一个 UTF-8字符。

当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32。 Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾

// 遍历字符串

func printStr() {
  str := "abcdefg 哈哈哈"
  for i := 0; i < len(str); i++ { // byte 1字节
    fmt.Printf("%v(%c)", str[i], str[i])
  }
  fmt.Println()
  fmt.Println("==========")
  for _, r := range str { // rune 4字节 单个字符
    fmt.Printf("%v(%c)", r, r)
  }
}
复制代码

输出:

97(a)98(b)99(c)100(d)101(e)102(f)103(g)32( )229(å)147()136()229(å)147()136()229(å)147()136()
==========
97(a)98(b)99(c)100(d)101(e)102(f)103(g)32( )21704(哈)21704(哈)21704(哈)
复制代码

因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。

字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由4个byte组成。

2.10 修改字符串

要修改字符串,需要先将其转换成[]rune或[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。

func changeStr() {
  str1 := "hello 你好"
  byte1 := []byte(str1)
  fmt.Println(string(byte1)) // 强转
  byte1[0] = 'H'
  byte1[1] = 'H'
  fmt.Println(string(byte1)) // 强转

  str2 := "你好"
  rune2 := []rune(str2)
  fmt.Println(string(rune2)) // 强转
  rune2[0] = '我'
  fmt.Println(string(rune2)) // 强转
}
复制代码

运行结果

hello 你好
HHllo 你好
你好
我好
复制代码

2.11 类型转换

Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用。

强制类型转换的基本语法如下:

T(表达式)

其中,T表示要转换的类型。表达式包括变量、复杂算子和函数返回值等.

比如计算直角三角形的斜边长时使用math包的Sqrt()函数,该函数接收的是float64类型的参数,而变量a和b都是int类型的,这个时候就需要将a和b强制类型转换为float64类型。

func sqrtDemo() {
  var a, b = 3, 4
  var c int
  // math.Sqrt()接收的参数是float64类型,需要强制转换
  c = int(math.Sqrt(float64(a*a + b*b)))
  fmt.Println(c)
}
复制代码

支持的类型转换

注释了的都是不能转到

func changeVarType() {

  // var v = "dd"
  // fmt.Println(int(v))
  // fmt.Println(byte(v))
  // fmt.Println(rune(v))
  // fmt.Println(float32(v))

  var v = 'D'
  fmt.Println(string(v))
  fmt.Println(byte(v))
  fmt.Println(float32(v))
  // fmt.Println(bool(v))
  // fmt.Println(complex64(v))
}
复制代码

类型断言

变量.(type),有两个返回值,第一个是对应类型的值,第二个是bool类型的,类型判断是否正确。

func printType() {
  var a interface{} = "value" // interface{} 代表变量可以是任何类型,不这么些,执行时会报错
  val, isInt := a.(int)
  fmt.Println(val, isInt)

  val2, isString := a.(string)
  fmt.Println(val2, isString)
}

// 结果
0 false
value true
复制代码

switch断言

func caseType() {
  var v interface{} = "string"

  switch v.(type) {
  case int:
    fmt.Print("int")
  case string:
    fmt.Print("string")
  }
}
复制代码

参考文章

Go语言的基本数据类型 - 知乎 (zhihu.com)

golang的强制类型转换 - Go语言中文网 - Golang中文社区 (studygolang.com)