package c2
import "fmt"
import "strconv"
/*
这个文件对Go语言变量相关的语句给出了一些示例程序。
*/
// 变量定义
func ExampleDeclaration1() {
var v1 int
fmt.Println("v1 =", v1)
var v2 string = "v2"
fmt.Println("v2 =", v2)
var v3 [10]int // 定义定长int数组
fmt.Println("v3 =", v3)
var v4 []int // 定义Slice
fmt.Println("v4 =", v4)
var v5 struct {
f int
}
fmt.Println("v5 =", v5)
var v6 *int
fmt.Println("v6 =", v6)
var v7 map[string]int
fmt.Println("v7 =", v7)
// 多重声明
var (
v9 int
v10 string
)
v10 = "v10"
fmt.Println("v9 =", v9)
fmt.Println("v10 =", v10)
// 多重声明的另一种方式
var a, b, c = 3, 4, "foo"
fmt.Println("a =", a)
fmt.Println("b =", b)
fmt.Println("c =", c)
// Output:
// v1 = 0
// v2 = v2
// v3 = [0 0 0 0 0 0 0 0 0 0]
// v4 = []
// v5 = {0}
// v6 = <nil>
// v7 = map[]
// v9 = 0
// v10 = v10
// a = 3
// b = 4
// c = foo
}
// 变量定义
func ExampleDeclaration2() {
// 定义带默认值的变量,这里会提示使用自动推导类型
var v11 int = 11
fmt.Println("v11 =", v11)
// 自动推导变量类型
var v12 = 12
fmt.Println("v12 =", v12)
// 自动推导变量类型,关键字:=用来明确表达同时进行变量声明和初始化的工作
// 不能对已经声明的变量使用:=运算符,这样会导致编译错误,如
// v12 :=12 // no new variables on left side of :=
v13 := 13
fmt.Println("v13 =", v13)
// 常量,这里不能使用:=
// go语言中的常量和C++一样,必须是编译器能获得的值
const v14 = 14
fmt.Println("v14 =", v14)
const v15 int = 15
fmt.Println("v15 =", v15)
// Output:
// v11 = 11
// v12 = 12
// v13 = 13
// v14 = 14
// v15 = 15
}
// 变量定义
func ExampleDeclaration3() {
// 预定义常量:true,false和iota,由于Go语言不支持枚举
// 因此这个操作可以用来实现枚举类型
// bool类型不支持隐式转换或者强制转换,自动推导类型必须使用逻辑表达式
boolTrue := true
fmt.Println("boolTrue =", boolTrue)
boolFalse := false
fmt.Println("boolFalse =", boolFalse)
const (
c0 = iota // 每个()中开始被重置为0
c1 = iota
c2 = iota
OutVariable // 大写开头的变量,包内外均可见
insideVariable // 小写开头的变量,仅包内可见
)
fmt.Println("c0 =", c0)
fmt.Println("c1 =", c1)
fmt.Println("c2 =", c2)
// iota还可以放入表达式
const (
cc0 = 1 << iota
cc1 // 如果表达式是一样的,后面可以不用填写,会保持和之前的一样
cc2 = 2 << iota
cc3 // 同上
)
fmt.Println("cc0 =", cc0)
fmt.Println("cc1 =", cc1)
fmt.Println("cc2 =", cc2)
fmt.Println("cc3 =", cc3)
// 如果在括号()外面,iota每次都是0
const iotaValue1 = iota
const iotaValue2 = iota
fmt.Println("iotaValue1 =", iotaValue1)
fmt.Println("iotaValue2 =", iotaValue2)
// Output:
// boolTrue = true
// boolFalse = false
// c0 = 0
// c1 = 1
// c2 = 2
// cc0 = 1
// cc1 = 2
// cc2 = 8
// cc3 = 16
// iotaValue1 = 0
// iotaValue2 = 0
}
func ExampleDeclaration4() {
// int32这样的类型不能直接赋值给int类型,尽量推荐使用int类型?
var int32Value int32 = 4
intValue := 5
// cannot use int32Value (type int32) as type int in assignment
// intValue =int32Value
// 但是可以强制转换,注意强制转换的语法,不是C语言的风格,是C++的风格
intValue = int(int32Value)
int32Value = int32(intValue)
// 并且不同类型的数值不能直接比较,也需要强制转换
// invalid operation: intValue ==int32Value (mismatched types int and int32)
// if intValue ==int32Value {
if intValue == int(int32Value) {
// 其他操作
}
}
// 复数类型
func ExampleComplex() {
var complexValue = 3.2 + 12i
fmt.Println("complexValue =", complexValue)
fmt.Println("real(complexValue) =", real(complexValue))
fmt.Println("imag(complexValue) =", imag(complexValue))
// TODO:复数如何在Printf中打印?
// Output:
// complexValue = (3.2+12i)
// real(complexValue) = 3.2
// imag(complexValue) = 12
}
// 字符串
func ExampleString() {
// 字符串的处理方法和C++差不多
str := "string"
ch := str[0]
fmt.Printf("str[%s],str[0]=[%c],len(str)=[%d]\n", str, ch, len(str))
// 但是字符串的内容不能在初始化后修改
// cannot assign to str[0]
// str[0] = '1'
str1 := str + "string2"
fmt.Println("str1 =", str1) // str1 = stringstring2
// 字符串可以直接相加
str = "hello" + " " + "world"
/* 字符串遍历 */
str = "Hello,世界"
// 字节遍历,字符串的长度和遍历都不会像C语言那样有结束符\0
n := len(str)
// 自增不能用++i,必须使用i++,
// unexpected ++, expecting expression
// for i := 0; i < n; ++i {
for i := 0; i < n; i++ {
fmt.Println(i, str[i])
}
fmt.Println("字节长度:", n)
// 字符遍历,一个UTF8字符只遍历一次
n = 0
for i, ch := range str {
fmt.Println(i, ch) // 这里ch的类型是rune?如何转换为字符?
}
fmt.Println("字符长度:", n)
// Output:
// str[string],str[0]=[s],len(str)=[6]
// str1 = stringstring2
// 0 72
// 1 101
// 2 108
// 3 108
// 4 111
// 5 44
// 6 228
// 7 184
// 8 150
// 9 231
// 10 149
// 11 140
// 字节长度: 12
// 0 72
// 1 101
// 2 108
// 3 108
// 4 111
// 5 44
// 6 19990
// 9 30028
// 字符长度: 0
}
// 变量赋值
func ExampleAssignment() {
// 普通赋值
v1 := 1
v1 = -1
fmt.Println("v1 =", v1)
// 多重赋值,大量运用在函数的返回值中
v2 := 2
fmt.Println("v2 =", v2)
v1, v2 = v2, v1
fmt.Println("v1, v2交换后:")
fmt.Println("v1 =", v1)
fmt.Println("v2 =", v2)
// Output:
// v1 = -1
// v2 = 2
// v1, v2交换后:
// v1 = 2
// v2 = -1
}
// 数组
func ExampleArray() {
// Go语言的数组是值类型
// 如果将数组作为参数传递,会产生一次复制操作,这点和C++不一样,要注意
// 如果想在参数中传递数组,可以使用数组切片
// 多维数组
var array3_5 [3][5]int
// 可以直接打印多维数组
fmt.Println("array3_5 =", array3_5)
fmt.Println("len(array3_5) =", len(array3_5))
fmt.Println("len(array3_5[0]) =", len(array3_5[0]))
// 使用len获得数组长度是一个O(1)的操作,因为这个长度是存储在数组类型内置常量中的
for i := 0; i < len(array3_5); i++ {
for j := 0; j < len(array3_5[i]); j++ {
array3_5[i][j] = i * j
}
}
// 数组的遍历,可以使用%d打印数组
for i, vi := range array3_5 {
fmt.Printf("array3_5[%d]=%d\n", i, vi)
for j, vj := range vi {
fmt.Printf("array3_5[%d][%d]=%d\n", i, j, vj)
}
}
// Output:
// array3_5 = [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
// len(array3_5) = 3
// len(array3_5[0]) = 5
// array3_5[0]=[0 0 0 0 0]
// array3_5[0][0]=0
// array3_5[0][1]=0
// array3_5[0][2]=0
// array3_5[0][3]=0
// array3_5[0][4]=0
// array3_5[1]=[0 1 2 3 4]
// array3_5[1][0]=0
// array3_5[1][1]=1
// array3_5[1][2]=2
// array3_5[1][3]=3
// array3_5[1][4]=4
// array3_5[2]=[0 2 4 6 8]
// array3_5[2][0]=0
// array3_5[2][1]=2
// array3_5[2][2]=4
// array3_5[2][3]=6
// array3_5[2][4]=8
}
// 数组切片
func ExampleSlice() {
// 数组切片可以看做:
// 指向原生数组的指针+数组切片中的元素个数+已分配的存储空间的集合
// 简单来说,就像STL的vector
myArray := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 创建数组切片
// 取数组前2个值的区间
fmt.Println("myArray[:2]:", myArray[:2])
// 取数组从索引1开始到末尾的区间
fmt.Println("myArray[1:]:", myArray[1:])
// 取数组[2,4)的区间,注意,不包含4
fmt.Println("myArray[2:4]:", myArray[2:4])
// 所有数组生成一个数组切片
fmt.Println("myArray[:]:", myArray[:])
// 自动推导类型,创建数组切片
mySlice := myArray[:5]
fmt.Println("mySlice:", mySlice)
// 直接创建元素个数为5的数组切片
// 如果格式不正确,输出结果会提示格式不正确,并且输出正确的类型[%!s(int=0)]
// 数组可以使用数组元素的类型进行输出
mySlice1 := make([]int, 5)
fmt.Printf("mySlice1,d: %d\n", mySlice1)
fmt.Printf("mySlice1,s: %s\n", mySlice1)
fmt.Printf("mySlice1[0]: %s\n", mySlice1[0])
// 直接创建元素个数为5的数组切片,元素为字符串
// 这样遍历的i是数组切片下标,并不是数组切片内容
// strconv.Itoa可以将数字转换为字符串
mySliceStr := make([]string, 5)
for i := range mySliceStr {
mySliceStr[i] = "str" + strconv.Itoa(i)
}
fmt.Printf("mySliceStr,d: %d\n", mySliceStr)
fmt.Printf("mySliceStr,s: %s\n", mySliceStr)
// 创建的时候初始化
mySlice2 := []int{1, 2, 3, 4, 5, 6}
fmt.Printf("mySlice2: %d\n", mySlice2)
// 获得容量
fmt.Printf("cap(mySliceStr): %d\n", cap(mySliceStr))
fmt.Printf("cap(mySlice2): %d\n", cap(mySlice2))
// 在末尾添加元素
mySlice2 = append(mySlice2, 1, 2, 3)
fmt.Printf("mySlice2: %d\n", mySlice2)
// 在末尾添加另一个数组切片,注意后面要有3个点,表示取数组中所有元素?
mySlice2 = append(mySlice2, mySlice2...)
fmt.Printf("mySlice2: %d\n", mySlice2)
// 数组切片的复制,如果2个数组切片不一样大
// 那么会按照其中较小的那个数组切片的元素个数进行复制
// 这是个坑,避免踩!
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1)
fmt.Printf("slice2: %d\n", slice2)
copy(slice1, slice2)
fmt.Printf("slice1: %d\n", slice1)
// Output:
// myArray[:2]: [0 1]
// myArray[1:]: [1 2 3 4 5 6 7 8 9]
// myArray[2:4]: [2 3]
// myArray[:]: [0 1 2 3 4 5 6 7 8 9]
// mySlice: [0 1 2 3 4]
// mySlice1,d: [0 0 0 0 0]
// mySlice1,s: [%!s(int=0) %!s(int=0) %!s(int=0) %!s(int=0) %!s(int=0)]
// mySlice1[0]: %!s(int=0)
// mySliceStr,d: [%!d(string=str0) %!d(string=str1) %!d(string=str2) %!d(string=str3) %!d(string=str4)]
// mySliceStr,s: [str0 str1 str2 str3 str4]
// mySlice2: [1 2 3 4 5 6]
// cap(mySliceStr): 5
// cap(mySlice2): 6
// mySlice2: [1 2 3 4 5 6 1 2 3]
// mySlice2: [1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 1 2 3]
// slice2: [1 2 3]
// slice1: [1 2 3 4 5]
}
// GetName 多重返回值函数
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
// 匿名变量,可用于过滤不需要的返回值
func ExampleAnonymityVeriable() {
_, _, nickName := GetName()
fmt.Println("nickName =", nickName)
// Output:
// nickName = Chibi Maruko
}
// map,Go语言内置类型
type PersonInfo struct {
ID string
Name string
Address string
}
func ExampleMap() {
// 创建一个map,类型格式:map[KeyType]ValueType
var personDB map[string]PersonInfo
personDB = make(map[string]PersonInfo)
// 创建方法2:使用make搭配:=操作符
personDB2 := make(map[string]PersonInfo)
// 填充内容到map
personDB["12345"] = PersonInfo{"12345", "Tom", "Room 203"}
personDB["1"] = PersonInfo{"1", "Jack", "Room 101"}
// 查找
person, ok := personDB["1234"]
fmt.Printf("personDB[\"1234\"]= %s, ok=%t\n", person, ok)
key := "1"
person, ok = personDB[key]
fmt.Printf("personDB[\"%s\"]= %s, ok=%t\n", key, person, ok)
// 引用关系
personDB2 = personDB
// 直接打印,每次结果可能会不一致,所以这里不打印了:
// 结果:personDB2 = map[12345:{12345 Tom Room 203} 1:{1 Jack Room 101}]
// fmt.Println("personDB2 =", personDB2)
key = "12345"
person, ok = personDB2[key]
fmt.Printf("personDB2[\"%s\"]= %s, ok=%t\n", key, person, ok)
// 修改personDB,personDB2也会跟着修改,因为二者引用的是同一个对象
personDB["3"] = PersonInfo{"3", "Rose", "Room 301"}
// 结果:personDB2 = map[12345:{12345 Tom Room 203} 1:{1 Jack Room 101} 3:{3 Rose Room 301}]
// fmt.Println("personDB2 =", personDB2)
// 定义容量为100的map
myMap := make(map[string]PersonInfo, 100)
fmt.Println("myMap =", myMap)
// 创建并且初始化map
myMap2 := map[string]PersonInfo{
"1234": PersonInfo{"1", "Haha", "Addr1"},
"2345": PersonInfo{"2345", "Hehe", "Addr2"}, // ******************注意这里这个逗号必不可少,强迫症有点受不了,不过添加项目的时候比较方便******************
}
fmt.Println("myMap2[\"1234\"] =", myMap2["1234"])
// 元素删除,delete的第一个参数必须是map
delete(myMap2, "1234")
_, ok = myMap2["1234"]
fmt.Println("ok =", ok)
// Output:
// personDB["1234"]= { }, ok=false
// personDB["1"]= {1 Jack Room 101}, ok=true
// personDB2["12345"]= {12345 Tom Room 203}, ok=true
// myMap = map[]
// myMap2["1234"] = {1 Haha Addr1}
// ok = false
}