var a, b *int
var (
a int
b string
c []float32
d func() bool
e struct {
x int
}
)
i, j := 0, 1
6.变量初始化的标准格式
//var 变量名 类型 = 表达式
var hp int = 100
var hp = 100
//短变量声明并初始化
//如果 hp 已经被声明过,但依然使用:=时编译器会报错
hp := 100
var a int = 100
var b int = 200
b, a = a, b
10.匿名变量的特点是一个下画线“”,“”本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,匿名变量不占用内存空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。
a, _ := 1, 2
_, b := 3, 4
11.函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量都属于局部变量。
12. 在函数体外声明的变量称之为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用“import”关键字引入全局变量所在的源文件之后才能使用这个全局变量。
13. 全局变量声明必须以 var 关键字开头,如果想要在外部包中使用全局变量的首字母必须大写。
14. 一个 float32 类型的浮点数可以提供大约 6 个十进制数的精度,而 float64 则可以提供约 15 个十进制数的精度,通常应该优先使用 float64 类型
15. 一个布尔类型的值只有两种:true 或 false
16. 可以使用双引号""来定义字符串,字符串中可以使用转义字符来实现换行、缩进等效果
var str = "GO语言从入门到放弃\nGO语言从入门到放弃"
//两个字符串 s1 和 s2 可以通过 s := s1 + s2 拼接在一起
str += "\n"
//嵌入一个多行字符串时,就必须使用`反引号
const s = `
第一行
第二行
第三行
`
//(\x 总是紧跟着长度为 2 的 16 进制数)
var ch byte = 65 或 var ch byte = '\x41'
18.一个类型的值可以被转换成另一种类型的值
//类型 B 的值 = 类型 B(类型 A 的值)
//不同底层类型的变量相互转换时会引发编译错误(如将 bool 类型转换为 int 类型)
a := 5.0
b := int(a)
19.当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。指针变量通常缩写为 ptr
//Go语言中使用在变量名前面添加&操作符(前缀)来获取变量的内存地址
ptr := &v // v 的类型为 T
var cat int = 1
var str string = "banana"
fmt.Printf("%p %p", &cat, &str)
20.Go语言还提供了另外一种方法来创建指针变量,格式如下:
str := new(string)
*str = "Go语言教程"
fmt.Println(*str)
21.变量逃逸分析: 通过编译器分析代码的特征和代码的生命周期,决定应该使用堆还是栈来进行内存分配。
22. 变量的生命周期与变量的作用域有着不可分割的联系
23. Go语言中的常量使用关键字 const 定义,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型
//常量的值必须是能够在编译时就能够确定的
const pi = 3.14159 // 相当于 math.Pi 的近似值
24.iota 常量生成器: 在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加一。
type Weekday int
//周日将对应 0,周一为 1,以此类推。
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
//String() 方法的 ChipType 在使用上和普通的常量没有区别。
//当这个类型需要显示为字符串时,
//Go语言会自动寻找 String() 方法并进行调用。
func (c WeekDay) String() string{
switch c {
case Sunday:
return "Sunday"
}
}
//type TypeAlias = Type
// 将NewInt定义为int类型
type NewInt int
// 将int取一个别名叫IntAlias
type IntAlias = int
1.Go语言数组
var a [3]int // 定义三个整数的数组
fmt.Println(a[0]) // 打印第一个元素
fmt.Println(a[len(a)-1]) // 打印最后一个元素
// 打印索引和元素
for i, v := range a {
fmt.Printf("%d %d\n", i, v)
}
// 仅打印元素
for _, v := range a {
fmt.Printf("%d\n", v)
}
2.用一组值来初始化数组
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2}
//在数组的定义中,如果在数组长度的位置出现“...”省略号,
//则表示数组的长度是根据初始化值的个数来计算
q := [...]int{1, 2, 3}
//数组的长度是数组类型的一个组成部分,
//因此 [3]int 和 [4]int 是两种不同的数组类型,
//数组的长度必须是常量表达式,
//因为数组的长度需要在编译阶段确定。
q := [3]int{1, 2, 3}
q = [4]int{1, 2, 3, 4} // 编译错误:无法将 [4]int 赋给 [3]int
//如果两个数组类型相同(包括数组的长度,数组中元素的类型)的情况下,
//我们可以直接通过较运算符(== 和!=)来判断两个数组是否相等
// 声明一个二维整型数组,两个维度的长度分别是 4 和 2
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化数组中索引为 1 和 3 的元素
array = [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化数组中指定的元素
array = [4][2]int{1: {0: 20}, 3: {1: 41}}
var a = [3]int{1, 2, 3}
fmt.Println(a, a[1:2])
// 声明字符串切片
var strList []string
// 声明整型切片
var numList []int
// 声明一个空切片
var numListEmpty = []int{}
//如果需要动态地创建一个切片,可以使用 make() 内建函数,
a := make([]int, 2)
b := make([]int, 2, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b))
//用append为切片添加元素
var a []int
a = append(a, 1) // 追加1个元素
a = append(a, 1, 2, 3) // 追加多个元素, 手写解包方式
a = append(a, []int{1,2,3}...) // 追加一个切片, 切片需要解包
a = append([]int{0}, a...) // 在开头添加1个元素
// 在第i个位置插入x
a = append(a[:i], append([]int{x}, a[i:]...)...)
a = a[1:] // 删除开头1个元素
a = a[N:] // 删除开头N个元素
a = append(a[:i], a[i+1:]...) // 删除中间1个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素
a = []int{1, 2, 3}
a = a[:len(a)-1] // 删除尾部1个元素
a = a[:len(a)-N] // 删除尾部N个元素
//声明一个二维切片
var slice [][]int
//为二维切片赋值
slice = [][]int{{10}, {100, 200}}
var mapname map[keytype]valuetype
noteFrequency := map[string]float32 {
"C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
"G0": 24.50, "A0": 27.50, "B0": 30.87, "A4": 440}
//使用 delete() 函数从 map 中删除键值对
delete(map, 键)
l := list.New()
l.PushBack("fist")
l.PushFront(67)
// 尾部添加后保存元素句柄
element := l.PushBack("fist")
// 在fist之后添加high
l.InsertAfter("high", element)
// 在fist之前添加noon
l.InsertBefore("noon", element)
// 使用
l.Remove(element)
//遍历
for i := l.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}
11.指针、切片、映射、通道、函数和接口的零值则是 nil。Go语言中的 nil 和其他语言中的 null 有很多不同点
//nil 标识符是不能比较的
nil == nil //报错
//nil 不是关键字或保留字
var nil = errors.New("my god")
//不同类型的 nil 值占用的内存大小可能是不一样的
var p *struct{}
fmt.Println( unsafe.Sizeof( p ) ) // 8
12.new 函数不仅仅能够为系统默认的数据类型,分配空间,自定义类型也可以使用 new 函数来分配空间
type Student struct {
name string
age int
}
var s *Student
//如果我们不使用 new 函数为自定义类型分配空间就会报错
s = new(Student) //分配空间
s.name ="dequan"
fmt.Println(s)
sum := 0
for i := 0; i < 10; i++ {//左花括号{必须与 for 处于同一行。
sum += i
}
//写法2
for {
sum++
if sum > 100 {
break
}
}
//初始语句可以被忽略,但是初始语句之后的分号必须要写
step := 2
for ; step > 0; step-- {
fmt.Println(step)
}
//只有一个循环条件的循环
for i <= 10 {
i++
}
func 函数名(形式参数列表)(返回值列表){
函数体
}
func hypot(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
//connectToNetwork 返回两个参数,conn 表示连接对象,err 返回错误信息。
conn, err := connectToNetwork()
func fire() {
fmt.Println("fire")
}
func main() {
var f func()
f = fire
f()
}
func(参数列表)(返回参数列表){
函数体
}
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
//任意类型的可变参数
func Printf(format string, args ...interface{}) {
// ...
}
// 将defer放入延迟调用栈
defer fmt.Println(1)
defer fmt.Println(2)
// 最后一个放入, 位于栈顶, 最先调用
defer fmt.Println(3)
//输出结果是3 2 1
var err = errors.New("this is an error")
package main
func main() {
panic("crash")
}
type 类型名 struct {
字段1 字段1类型
字段2 字段2类型
…
}
//基本实例化格式如下
var ins T
type Point struct {
X int
Y int
}
var p Point
p.X = 10
p.Y = 20
//创建指针类型的结构体
ins := new(Point)
//对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作
ins := &Point{}
type People struct {
name string
child *People
}
relation := &People{
name: "爷爷",
child: &People{
name: "爸爸",
child: &People{
name: "我",
},
},
}
type Address struct {
Province string
City string
ZipCode int
PhoneNumber string
}
addr := Address{
"四川",
"成都",
610000,
"0",
}
msg := &struct { // 定义部分
id int
data string
}{ // 值初始化部分
1024,
"hello",
}
type Bag struct {
items []int
}
//(b*Bag) 表示接收器,即 Insert 作用的对象实例
func (b *Bag) Insert(itemid int) {
b.items = append(b.items, itemid)
}
type innerS struct {
in1 int
in2 int
}
type outerS struct {
b int
c float32
int // anonymous field
innerS //继承
}
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
package main
import (
"fmt"
)
// 定义一个数据写入器
type DataWriter interface {
WriteData(data interface{}) error
}
// 定义文件结构,用于实现DataWriter
type file struct {
}
// 实现DataWriter接口的WriteData方法
func (d *file) WriteData(data interface{}) error {
// 模拟写入数据
fmt.Println("WriteData:", data)
return nil
}
func main() {
// 实例化file
f := new(file)
// 声明一个DataWriter的接口
var writer DataWriter
// 将接口赋值f,也就是*file类型
// writer 是一个接口,且 f 已经完全实现了 DataWriter() 的所有方法,因此赋值是成功的。
writer = f
// 使用DataWriter接口进行数据写入
writer.WriteData("data")
}
var x interface{}
x = 10
//如果不接收第二个参数,断言失败时会直接造成一个 panic。如果 x 为 nil 同样也会 panic
value, ok := x.(int)
//10, true
fmt.Print(value, ",", ok)
//第二种断言方式
func getType(a interface{}) {
switch a.(type) {
case int:
fmt.Println("the type of a is int")
case string:
fmt.Println("the type of a is string")
case float64:
fmt.Println("the type of a is float")
default:
fmt.Println("unknown type")
}
}
type error interface {
Error() string
}
//全路径
import "lab/test"
//相对路径
import "../a"
//别名引用方式
import F "fmt"
//省略方式:相当于把包 fmt 的命名空间直接合并到当前程序的命名空间中,
//使用 fmt 包内可导出元素可以不用前缀“fmt.”,直接引用
import . "fmt"
//使用标准格式引用包,但是代码中却没有使用包,编译器会报错。
//如果包中有 init 初始化函数,则通过 import _ "packageName" 这种方式引用包,
//仅执行包的初始化函数,即使包没有 init 初始化函数,也不会引发编译器报错
import _ "fmt"
结构体内的小写字母开头的成员不能被外部直接访问
GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。
在 Go语言里,允许我们将同一个包的代码分隔成多个小块来单独保存,只需要将这些文件放在同一个目录即可。
如果想在一个包里引用另外一个包里的标识符(如类型、变量、常量等)时,必须首先将被引用的标识符导出,将要导出的标识符的首字母大写就可以让引用者可以访问这些标识符了
//单行导入
import "包1"
//多行导入
import(
"包1"
"包2"
…
)
go func(idx int) {
lock.Lock()
defer lock.Unlock()
a += 1
fmt.Printf("goroutine %d, a=%d\n", idx, a)
}(i)
//创建读写锁
var rw sync.RWMutex
rw.RLock()
fmt.Printf("goroutine %d 进入读操作...\n", n)
v := count
fmt.Printf("goroutine %d 读取结束,值为:%d\n", n, v)
rw.RUnlock()
big1, _ := new(big.Int).SetString("1000", 10)
fmt.Println("big1 is: ", big1)
big2 := big1.Uint64()
fmt.Println("big2 is: ", big2)
go 函数名( 参数列表 )
//匿名函数
go func( 参数列表 ){
函数体
}( 调用参数列表 )
// runtime.NumCPU() 查询 CPU 数量,并使用 runtime.GOMAXPROCS() 函数进行设置
runtime.GOMAXPROCS(runtime.NumCPU())