Go语言是静态类型语言,因此变量(variable)是有明确类型的,编译器也会检查变量类型的正确性。
从计算机系统实现角度来看,变量是一段或多段用来存储数据的内存。
Go语言的基本类型:
Go语言声明:
var
关键字:var name type //var为声明变量关键字,type为变量类型,name为变量名
通过声明变量时将变量的类型放在变量名称后面,避免类型C语言中的含糊不清:int *a, b ;
,其中a为指针,b不是。
var a,b int* //均为指针
var
和括号,可以将一组变量定义放在一起。var (
a int
b string
c [ ]float32
d func( ) bool
e struct {
x int
}
)
名字 := 表达式
i, j := 0, 1
简短模式有以下限制:
Go语言在声明变量时,自动对变量对应的内存区域进行初始化操作。每个变量会初始化其类型的默认值,例如:整型和浮点型变量的默认值为 0 和 0.0。字符串变量的默认值为空字符串。布尔型变量默认为 bool。切片、函数、指针变量的默认为 nil。
C语言中,变量在声明时,并不会对变量对应内存区域进行清理操作。
微软的 VC 编译器会将未初始化的栈空间以 16 进制的 0xCC 填充,而未初始化的堆空间使用 0xCD 填充,而 0xCCCC 和 0xCDCD 在中文的 GB2312 编码中刚好对应“烫”和“屯”字。
Go语言变量初始化:
var hp int = 100
var hp = 100
将int省略后,编译器会尝试根据等号右边的右值表达式推导变量类型。需要注意的是,对于浮点型会自动推导为float64
类型。
hp := 100
注意事项同2.1中说明,这种方式为Go语言的推导声明写法,由于使用了:=
,而不是赋值符号=
,因此推导声明的左值变量必须是没有定义过的变量。
var hp int
hp:=100 //报错
从实际使用角度来说,短变量声明的形式比较多:
conn, err := net.Dial("tcp", "127.0.0.1:8080")
conn2, err := net.Dial("tcp", "127.0.0.1:8080")
var
,再使用(对于部分变量的应用场景而言)对于Go语言来说,这个阶段的开发环境中,内存不再是稀缺资源,所以对于交换变量而言:
var a int =100
var b int =200
a, b = b, a
fmt.Println( a, b )
多重赋值时,变量的左值和右值按从左到右的顺序赋值。
通过使用匿名变量,在一些应用场景下增强代码的灵活性。
Go语言的匿名变量的特点是一个下划线 _
,_
本身就是一个特殊的标识符,被称为空白标识符。
它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。
类似Linux中重定向/dev/null的作用。匿名变量在某些函数接口中充当占位,而后续又不需要该接口返回的信息。
提示:在 Lua 等编程语言里,匿名变量也被叫做哑元变量。
func GetData() (int, int) {
return 100, 200
}
func main() {
a, _ := GetData() //通过匿名变量,200被丢弃
_, b := GetData() //通过匿名变量,100被丢弃
fmt.Println(a, b)
}
一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。
学习过C++的应该能很快理解。
作用域之间的嵌套影响同C++,内层屏蔽外层。
根据变量定义位置(作用范围)的不同,可以分为以下三个类型:
Go语言的数值类型分为:整数、浮点数、复数。
Go语言同时提供了有符号和无符号的整数类型,其中包括:
int8、int16、int32 和 int64
四种大小截然不同的有符号整数类型,分别对应 8、16、32、64 bit(二进制位)大小的有符号整数uint8、uint16、uint32 和 uint64
四种无符号整数类型。 int 和 uint
,它们分别对应特定 CPU 平台的字长。根据不同平台可能为4字节或者8字节。int8
的范围为-128到127rune
类型和 int32
类型是等价的,通常用于表示一个 Unicode 码点。这两个名称可以互换使用。byte
和uint8
也是等价类型,byte 类型一般用于强调数值是一个原始的数据而不是一个小的整数。在涉及不同平台时,为了减少编译目标平台字节长度的影响,不要使用int
和unit
。
math
包中可以查看不同数值类型的最大和最小值:
fmt.Println(math.MaxInt32)
Go语言提供了两种精度的浮点数 float32 和 float64,它们的算术规范由 IEEE754 浮点数国际标准定义:
var f float32 = 16777216 // 1 << 24
fmt.Println(f == f+1) // "true"! 精度误差
//只写小数或者整数部分
const e = .71828 // 0.71828
const f = 1. // 1
//使用科学计数法
const Avogadro = 6.02214129e23 // 阿伏伽德罗常数
const Planck = 6.62606957e-34 // 普朗克常数
在计算机中,复数是由两个浮点数表示的,其中一个表示实部(real),一个表示虚部(imag)。
Go语言中复数的类型有两种,分别是 complex128(64 位实数和虚数)和 complex64(32 位实数和虚数),其中 complex128 为复数的默认类型。实部和虚部部分都为浮点类型。
var name complex128 = complex(32.1, 42,1) //complex 为Go语言的内置函数用于为复数赋值
name:=complex(x, y) //简化模式
var x complex128 = complex(1, 2) // 1+2i
fmt.Println(real(x)) //实部
fmt.Println(imag(x)) //虚部
==
和!=
进行比较。一个布尔类型的值只有两种:true 或 false。if 和 for 语句的条件部分都是布尔类型的值,并且==
和<
等比较操作也会产生布尔型的值。
布尔值可以和 &&(AND)和 ||(OR)操作符结合,并且有短路行为:如果运算符左边的值已经可以确定整个布尔表达式的值,那么运算符右边的值将不再被求值。
&&
的优先级比||
高(&& 对应逻辑乘法,|| 对应逻辑加法)
Go语言中不允许将整型强制转换为布尔型。布尔型无法参与数值运算,也无法与其他类型进行转换。如果有需要,可以自己将该功能封装成函数。
var n bool
fmt.Println(int(n) * 2) //编译错误
Unicode 与 ASCII 类似,都是一种字符集。字符集为每个字符分配一个唯一的 ID,我们使用到的所有字符在 Unicode 字符集中都有一个唯一的 ID。
UTF-8 是变长编码规则,将 Unicode 中字符的 ID 以某种方式进行编码,从 1 到 4 个字节不等。编码规则如下:
根据这个规则,拉丁文语系的字符编码一般情况下每个字符占用一个字节,而中文每个字符占用 3 个字节。
使用""
双引号来定义字符串,字符串中可以使用常用的转义字符
使用反引号来定义跨行字符串,其中的所有转义字符均无效,用于内嵌源码等
const str = `第一行
第二行
第三行
\r\n
`
字符串拼接符号:
str := "Beginning of the string " +
"second part of the string"
//因为编译器会在行尾自动补全分号,所以拼接字符串用的加号“+”必须放在第一行末尾。
一般的比较运算符(==、!=、<、<=、>=、>)是通过在内存中按字节比较来实现字符串比较的
字符串所占的字节长度可以通过函数 len()
来获取,索引下标从0开始(对纯ASCII码字符串有意义),不允许获取某个其中某个字节的地址&str[ i ]
Go 语言的内建函数 len()
,可以用来获取切片、字符串、通道(channel)等的长度。
但是由于Go 语言的字符串都以 UTF-8 格式保存,每个中文占用 3 个字节,使用这种方式获取的字符串长度往往并不符合实际预期。使用RuneCountInString()
函数,统计 Uncode 字符数量。
fmt.Println(utf8.RuneCountInString("忍者"))
theme := "狙击 start"
for i := 0; i < len(theme); i++ {
fmt.Printf("ascii: %c %d\n", theme[i], theme[i])
}
//这种方式下单个字节单个字节取内存,汉字显示为乱码
for range
theme := "狙击 start"
for _, s := range theme {
fmt.Printf("Unicode: %c %d\n", s, s)
}
利用 strings.Index()
函数和截取切片在字符串中搜索另外一个子串
tracer := "死神来了, 死神bye bye"
comma := strings.Index(tracer, ", ") //返回找到的位置
pos := strings.Index(tracer[comma:], "死神")
fmt.Println(comma, pos, tracer[comma+pos:])
strings.Index
:正向搜索子字符串。strings.LastIndex
:反向搜索子字符串。Go 语言的字符串无法直接修改每一个字符元素,只能通过重新构造新的字符串数组并赋值给原来的字符串变量实现。请参考下面的代码:
angel := "Heros never die"
angleBytes := []byte(angel)
for i := 5; i <= 10; i++ {
angleBytes[i] = ‘ ‘
}
fmt.Println(string(angleBytes))
+
可以进行拼接操作,但是效率并不高 StringBuilder
的机制来进行高效的字符串连接hammer := "吃我一锤"
sickle := "死吧"
// 声明字节缓冲
var stringBuilder bytes.Buffer
// 把字符串写入缓冲
stringBuilder.WriteString(hammer)
stringBuilder.WriteString(sickle)
// 将缓冲以字符串形式输出
fmt.Println(stringBuilder.String())
fmt.Sprintf(格式化样式, 参数列表…)
%
开头。动 词 | 功 能 |
---|---|
%v | 按值的本来值输出 |
%+v | 在 %v 基础上,对结构体字段名和值进行展开 |
%#v | 输出 Go 语言语法格式的值 |
%T | 输出 Go 语言语法格式的类型和值 |
%% | 输出 % 本体 |
%b | 整型以二进制方式显示 |
%o | 整型以八进制方式显示 |
%d | 整型以十进制方式显示 |
%x | 整型以十六进制方式显示 |
%X | 整型以十六进制、字母大写方式显示 |
%U | Unicode 字符 |
%f | 浮点数 |
%p | 指针,十六进制方式显示 |
Go语言的字符有以下两种:
Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表字符):
Go语言不存在隐式类型转换,因此所有的类型转换都必须显式的声明:
valueOfTypeB = typeB(valueOfTypeA)
指针(pointer)在Go语言中可以被拆分为两个核心概念:
可以理解为前者为指针const,提供访问特定内存的方式;后者为指向的数据const,为迭代器的功能
当一个指针被定义后没有分配到任何变量时,它的默认值为 nil
。
当使用&
操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*
操作符,也就是指针取值
创建指针的另一种方法——new() 函数,new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。
BSP
和ESP
指针的存在,对于整块内存的分配和回收会比较迅速生命周期和作用域为两个不同的概念,可能在其生命周期内却无法被使用了。
Go语言中的常量使用关键字 const 定义,用于存储不会改变的数据,常量是在编译时被创建的。定义常量的表达式必须为能被编译器求值的常量表达式。
const b string = "abc" //显式类型定义
const b="abc" //隐式类型定义
如果没有显式指明类型,那么将从右边的表达式推断类型:
const noDelay time.Duration = 0
const timeout = 5 * time.Minute
fmt.Printf("%T %[1]v\n", noDelay) // "time.Duration 0"
fmt.Printf("%T %[1]v\n", timeout) // "time.Duration 5m0s"
fmt.Printf("%T %[1]v\n", time.Minute) // "time.Duration 1m0s"
批量声明常量:
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // "1 1 2 2"
iota常量生成器:
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加一。
无类型常量:
编译器为没有明确的基础类型的数字常量提供比基础类型更高精度的算术运算,可以认为至少有 256bit 的运算精度。这里有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。
通过延迟明确常量的具体类型,不仅可以提供更高的运算精度,而且可以直接用于更多的表达式而不需要显式的类型转换。
var x float32 = math.Pi
var y float64 = math.Pi
var z complex128 = math.Pi
区别类型别名和类型定义
type TypeAlias = Type //类型别名
type TypeNew Type //类型定义
类型别名规定:TypeAlias 只是 Type 的别名,本质上 TypeAlias 与 Type 是同一个类型
package main
import (
"fmt"
)
// 将NewInt定义为int类型
type NewInt int
// 将int取一个别名叫IntAlias
type IntAlias = int
func main() {
// 将a声明为NewInt类型
var a NewInt
// 查看a的类型名
fmt.Printf("a type: %T\n", a) // NewInt
// 将a2声明为IntAlias类型
var a2 IntAlias
// 查看a2的类型名
fmt.Printf("a2 type: %T\n", a2) //int
}
import (
"time"
)
// 定义time.Duration的别名为MyDuration
type MyDuration = time.Duration
// 为MyDuration添加一个函数
func (m MyDuration) EasySet(a string) {
}
编译器提示:不能在一个非本地的类型 time.Duration 上定义新方法,非本地类型指的就是 time.Duration 不是在 main 包中定义的,而是在 time 包中定义的,与 main 包不在同一个包中,因此不能为不在一个包中的类型定义方法。
//
单行注释/**/
多行注释godoc
工具:可以从 Go 程序和包文件中提取顶级声明的首行注释以及每个对象的相关注释,并生成相关文档Go语言的词法元素包括 5 种,分别是标识符(identifier)、关键字(keyword)、操作符(operator)、分隔符(delimiter)、字面量(literal),它们是组成Go语言代码和程序的最基本单位。
http://c.biancheng.net/view/5559.html
strconv 包中常用的函数包括 Atoi()、Itia()、parse 系列函数、format 系列函数、append 系列函数等
Itoa()
:整型转字符串func main() {
num := 100
str := strconv.Itoa(num)
fmt.Printf("type:%T value:%#v\n", str, str)
}
Atoi()
:字符串转整型func Atoi(s string) (i int, err error) //err 在转换成功是为空转换失败时为相应的错误信息。
Parse 系列函数用于将字符串转换为指定类型的值,其中包括 ParseBool()、ParseFloat()、ParseInt()、ParseUint()。
Format 系列函数实现了将给定类型数据格式化为字符串类型的功能,其中包括 FormatBool()、FormatInt()、FormatUint()、FormatFloat()。
http://c.biancheng.net/view/5112.html
------------恢复内容结束------------
原文:https://www.cnblogs.com/tlam/p/14998521.html