目录
1、init函数和main函数
相同点:
两个函数在定义时不能有任何的参数和返回值,且Go程序自动调用。
不同点:
init可以应用于任意包中,且可以重复定义多个。
main函数只能用于main包中,且只能定义一个。
两个函数的执行顺序:
调用顺序:
对同一个go文件的init()调用顺序是从上到下的。
对同一个package中不同文件是按文件名字符串比较“从小到大”顺序调用各文件中的init()函数。
对于不同的package,如果不相互依赖的话,按照main包中"先import的后调用"的顺序调用其包中的init(),如果package存在依赖,则先调用最早被依赖的package中的init(),最后调用main函数。import _ 包路径 只是引用该包,仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数
import _ "./hello"
2、变量和常量
var 变量名 变量类型
批量声明用()
var (
a string
b int
)
类型推导:var name string = "pprof.cn"
短变量声明:n := 10
_ 匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明。 (在Lua等编程语言里,匿名变量也被叫做哑元变量。)
常量:var 换成 const
iota:是go语言的常量计数器,只能在常量的表达式中使用。 iota在const关键字出现时将被重置为0。const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用。
package main
import "fmt"
func iota_use1() {
//会顺延a,b的规则递增
const (
a, b = iota + 1, iota + 2 //1,2
c, d //2,3 iota=1,c=1+1,d=1+2
e, f //3,4
)
fmt.Printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d)
}
func iota_use2() {
//e会顺延d的规则递增
const (
a = iota //0
b //1
_
d = iota + 1 //3+1
e //4+1
)
fmt.Printf("a=%d,b=%d,d=%d,e=%d\n", a, b, d, e)
}
func iota_use3() {
//每当某个枚举被重置(即后面使用iota重新赋值时),则需要从第一个枚举数到当前的次序
const (
a = iota //0
b //1
_
d = iota + 1 //3+1=4
e //4+1=5
f = iota + 2 //5+2=7
g = iota //6
)
fmt.Printf("a=%d,b=%d,d=%d,e=%d,f=%d,g=%d\n", a, b, d, e, f, g)
}
func main() {
iota_use1()
iota_use2()
iota_use3()
}
3、基本类型:
byte和rune类型
uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
rune类型,代表一个 UTF-8字符。
字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。
修改字符串:
要修改字符串,需要先将其转换成[]rune或[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。
强制类型转换:T(表达式)
4、数组
1. 数组:是同一种数据类型的固定长度的序列。
2. 数组定义:var a [len]int,比如:var a [5]int,数组长度必须是常量,且是类型的组成部分。一旦定义,长度不能变。
3. 长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型。
4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
for i := 0; i < len(a); i++ {}
for index, v := range a {}
5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
6. 数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。
7.支持 "=="、"!=" 操作符,因为内存总是被初始化过的。
8.指针数组 [n]*T,数组指针 *[n]T。
内置函数 len 和 cap 都返回数组长度 (元素数量)。
package main
import (
"fmt"
"math/rand"
"time"
)
// byte和rune类型
// 遍历字符串
func traversalString() {
s := "pprof.cn博客"
for i := 0; i < len(s); i++ { //byte
fmt.Printf("%v(%c) ", s[i], s[i])
}
fmt.Println()
for _, r := range s { //rune
fmt.Printf("%v(%c) ", r, r)
}
fmt.Println()
}
// 修改字符串
// 要修改字符串,需要先将其转换成[]rune或[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。
// 强制类型转换:T(表达式)
func changeString() {
s1 := "hello"
// 强制类型转换
byteS1 := []byte(s1)
byteS1[0] = 'H'
fmt.Println(string(byteS1))
s2 := "博客"
runeS2 := []rune(s2)
runeS2[0] = '狗'
fmt.Println(string(runeS2))
}
// 112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 229(å) 141() 154() 229(å) 174(®) 162(¢)
// 112(p) 112(p) 114(r) 111(o) 102(f) 46(.) 99(c) 110(n) 21338(博) 23458(客)
// Hello
// 狗客
// 数组
func array_use() {
a := [3]int{1, 2} // 未初始化元素值为 0。
b := [...]int{1, 2, 3, 4} // 通过初始化值确定数组长度。
c := [5]int{2: 100, 4: 200} // 使用引号初始化元素。
d := [...]struct {
name string
age uint8
}{
{"user1", 10}, // 可省略元素类型。
{"user2", 20}, // 别忘了最后一行的逗号。
}
fmt.Println(a, b, c, d)
//多维
e := [2][3]int{{1, 2, 3}, {4, 5, 6}}
f := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 纬度不能用 "..."。
fmt.Println(e, f)
}
//值拷贝行为会造成性能问题,通常会建议使用 slice,或数组指针。
//什么拷贝内存地址都变了???
func test(x [2]int) {
fmt.Printf("值拷贝 x: %p\n", &x)
x[1] = 1000
}
func test2(x *[2]int) {
fmt.Printf("引用拷贝 x: %p\n", &x)
x[1] = 1000
}
func slice_copy(x []int) {
x[1] = 1000
fmt.Printf("slice拷贝 x: %p\n", &x)
}
func array_copy() {
a := [2]int{}
fmt.Printf("a: %p\n", &a)
test(a)
fmt.Println(a)
test2(&a)
fmt.Println(a)
b := []int{0, 0}
fmt.Printf("b: %p\n", &b)
slice_copy(b)
fmt.Println(b)
}
// 多维数组遍历
func arrays() {
var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
for k1, v1 := range f {
for k2, v2 := range v1 {
fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
}
fmt.Println()
}
}
// 练习1:求数组所有元素之和
func sumArr(a [10]int) int {
sum := 0
for i := 0; i < len(a); i++ {
sum += a[i]
}
return sum
}
// 练习1:求数组所有元素之和
func learn1() {
rand.Seed(time.Now().Unix())
var a [10]int
for i := 0; i < len(a); i++ {
// seed()种子默认是1
//产生一个0-100的随机数,包括100吗?
a[i] = rand.Intn(100)
}
sum := sumArr(a)
fmt.Println("sum=", sum)
}
// 练习2:
// 找出数组中和为给定值的两个元素的下标,例如数组[1,3,5,8,7],
// 找出两个元素之和等于8的下标分别是(0,4)和(1,2)
func findSum(a []int, x int) {
for i := 0; i < len(a); i++ {
for j := i + 1; j < len(a); j++ {
if a[i]+a[j] == x {
fmt.Printf("(%d,%d)\n", i, j)
}
}
}
}
func learn2() {
a := []int{1, 3, 5, 8, 7}
findSum(a, 8)
}
func main() {
// traversalString()
// changeString()
// array_use()
//array_copy()
//arrays()
learn2()
}