[TOC]
常见数据类型
值类型
 
值类型:基本数据类型int、float、bool、string、数组和结构体struct都属于值类型,使用这些类型的变量是直接使用指向存在内存中的值,值类型的变量的值通常存储在栈中
引用类型
引用类型:指针、slice切片、map、管道chan、interface等都是引用类型
字符串
golang的统一编码为utf-8,golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8,所以字母数字占一字节,汉字占3字节
要获取一个字符串的长度,有以下2种方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | package main
  import ( 	"fmt" 	"unicode/utf8" )
  func main() { 	str := "hello 芝麻开门" 	 	fmt.Println("str 的长度:", len(str))
  	fmt.Println("str 的RuneCountInString长度:", utf8.RuneCountInString(str)) 	fmt.Println("str 的rune convert长度:", len([]rune(str))) 	
 
 
 
  }
 
   | 
 
golang中还有一个byte数据类型,与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:
- byte 等同于int8,常用来处理ascii字符
 
- rune 等同于int32,常用来处理unicode或utf-8字符
 
- 循环一个字符串时,如果有中文,需要转切片,不然会出现乱码,因为是按照字符串的字节长度遍历
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
   | package main
  import ( 	"fmt" 	"unicode/utf8" )
  func main() { 	str := "hello 芝麻开门" 	 	fmt.Println("str 的长度:", len(str))
  	fmt.Println("str 的RuneCountInString长度:", utf8.RuneCountInString(str)) 	fmt.Println("str 的rune convert长度:", len([]rune(str))) 	
 
 
 
  	runeStr := []rune(str) 	for i := 0; i < len(runeStr); i++ { 		fmt.Printf("%c\n", runeStr[i]) 	} 	
 
 
 
 
 
 
 
 
 
 
 
 
 
       	 	fmt.Println(strings.Contains("hello world", "hello")) 
  	 	fmt.Println(strings.Count("hello world", "o")) 
  	 	fmt.Println(strings.EqualFold("hello world", "Hello World")) 
  	 	fmt.Println(strings.Index("hello world", "o")) 
  	 	fmt.Println(strings.LastIndex("hello world", "o")) 
  	 	fmt.Println(strings.Replace("hello world", "hello", "你好", 1)) 
  	 	strArr := strings.Split("hello world", "o w") 	fmt.Printf("strArr 类型 %T,值%v\n", strArr, strArr)  	for i := 0; i < len(strArr); i++ { 		fmt.Println(strArr[i]) 		
 
 
  	}
  	 	fmt.Println(strings.ToLower("HELLO WORLD"))  	fmt.Println(strings.ToUpper("hello world")) 
  	 	fmt.Println(strings.TrimRight("~hello world~", "~"))  	fmt.Println(strings.TrimLeft("~hello world~", "~"))   	fmt.Println(strings.Trim("~hello world~", "~"))      
  	 	fmt.Println(strings.HasPrefix("hello world", "hello"))  	fmt.Println(strings.HasSuffix("hello world", "hello")) 
  	 	fmt.Println(strings.Join(strArr, "o w")) 
  	 	fmt.Println(strings.Repeat("go ", 3))  }
 
   | 
 
数组
声明数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | func arrayDemo() { 	 	var arr [3]int = [3]int{1, 2, 3} 	arr1 := [3]int{1, 2, 3} 	fmt.Println(arr, arr1) 
  	 	arr2 := [...]int{5: -1} 	fmt.Println(arr2) 
  	 	var arr3 [3]int 	fmt.Println(arr3) 
  	 	arr4 := [3][2]int{} 	arr5 := [3][2]string{{"a", "b"}, {"AA", "BB"}, {"AAA", "BBB"}} 	fmt.Println(arr4, arr5) 
  	 	arr6 := new([3]int) 	fmt.Printf("arr6类型%T,值%v", arr6, arr6) 
  	arr7 := new([2]int) 	fmt.Printf("arr7类型%T,值%v" , arr7 , arr7)  }
  | 
 
遍历数组
1 2 3 4 5 6 7
   | func for_range() { 	arr := [...]string{"go", "php", "java"} 	for key, value := range arr { 		fmt.Printf("key = %v , value = %v", key, value) 		 	} }
  | 
 
slice切片
定义和创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | package main
  import "fmt"
  func main() {    sliceDemo1()    sliceDemo2()    sliceDemo3() } func sliceDemo1() {    var arr [5]int = [...]int{1, 2, 3, 4, 5}    var slice = arr[1:3]    // slice value=[2 3] , cap=4 , len=2    fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice)) } func sliceDemo2() {    var slice []int = make([]int, 5, 10)    fmt.Println(slice) // [0 0 0 0 0]    slice[1] = 5    slice[3] = 10    // slice value=[0 5 0 10 0] , cap=10 , len=5    fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice)) } func sliceDemo3() {    // 声明和初始化一个切片    var slice []string = []string{"hello", "world", "!"}    fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice)) }
   | 
 
三种方式说明及区别
说明
sliceDemo1:让切片引用一个已经存在的数组创建切片
sliceDemo2:使用make来创建,可以指定切片的大小和容量,如果没有给切片赋值,则会使用默认值,(int、float=>0, strint=>””, bool=>false);make方式创建的切片对应的数组由make底层维护,对外不开见,只能通过slice访问各个元素
sliceDemo3:定义一个切片直接指定具体数组
区别
sliceDemo1方式是直接引用数组,这个数组是事先存在的,对程序员可见
sliceDemo2通过make创建切片,make也会创建一个数组,是由切片在底层维护,该数组对程序员不可见    
冒泡排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
   | package main
  import "fmt"
  func main() { 	arr := [8]int{22, 31, 23, 44, 1, 55, 54, 33}     
 
 
 
  	fmt.Println(bubble1(arr)) 	fmt.Println(bubble2(arr)) 	fmt.Println(bubble3(arr)) } func bubble1(data [8]int) [8] int { 	for i := 0; i < len(data)-1; i++ { 		fmt.Println(data[i]) 		for j := 0; j < len(data)-1-i; j++ { 			if data[j] > data[j+1] { 				tmp := data[j] 				data[j] = data[j+1] 				data[j+1] = tmp 			} 		} 	} 	return data }
  func bubble2(data [8]int) [8]int { 	for i := 0; i < len(data); i++ { 		for j := i + 1; j < len(data); j++ { 			if data[i] > data[j] { 				tmp := data[i] 				data[i] = data[j] 				data[j] = tmp 			} 		} 	} 	return data } func bubble3(data [8]int) [8]int { 	for i := 0; i < len(data); i++ { 		for j := 0; j < len(data)-1; j++ { 			if data[j] > data[j+1] { 				tmp := data[j] 				data[j] = data[j+1] 				data[j+1] = tmp 			} 		} 	} 	return data }
 
   | 
 
map
map相当于PHP中的关联数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | package main
  import "fmt"
  func main() {    mapDemo() } func mapDemo() {        var map1 map[string]string    map1 = make(map[string]string, 5)    map1["name"] = "zhimma"    map1["address"] = "xian"    fmt.Println(map1) 
         map2 := make(map[string]string)    map2["name"] = "zhimma"    map2["address"] = "xian"    fmt.Println(map2) 
         map3 := map[string]string{       "name":    "zhimma",       "address": "xian",    }    fmt.Println(map3)  }
   | 
 
指针相关概念
变量:变量是基本类型,变量存的就是值,也叫值类型
地址:用于引用计算机的内存地址,可理解为内存地址的标签,通俗一点讲就是一个房子在小区门牌号
1 2 3 4 5 6 7 8 9 10
   | package main
  import "fmt"
  func main() {      	name := "zhimma" 	fmt.Println("name 的地址是", &name)  }
 
   | 
 
指针:指针变量存的是一个地址,这个地址指向的空间存的才是值,指针是一个指向另一个变量内存地址的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | package main
  import "fmt"
  func main() { 	var i int = 1 	fmt.Println("i 的地址是", &i)
  	var ptr *int = &i 	fmt.Printf("ptr=%v\n", ptr) 	fmt.Printf("ptr的地址是%v\n", &ptr) 	fmt.Printf("ptr指向的值是%v\n", *ptr)     
 
 
 
 
 
  }
 
   | 
 
&:取地址符,指针 := &变量
*:取值符, 变量 := *指针
匿名函数
定义匿名函数有2种方式
定义时直接使用(这种方式只使用一次)
1 2 3 4 5 6 7 8 9 10
   | package main
  import "fmt"
  func main() { 	totalNum := func(a int, b int) int { 		return a + b 	}(5, 3) 	fmt.Println(totalNum)  }
   | 
 
将匿名函数赋值给变量
1 2 3 4 5 6 7 8 9 10 11 12
   | package main
  import "fmt"
  func main() { 	 	sumFunc := func(a int, b int) int { 		return a + b 	} 	total := sumFunc(1, 2) 	fmt.Println(total) }
   | 
 
全局匿名函数
1 2 3 4 5 6 7 8 9 10 11 12
   | package main
  import "fmt"
  var globalFunc = func(params string) string { 	return "this is globalFunc and receive params str is'" + params + "'" }
  func main() { 	str := globalFunc("hello world") 	fmt.Println(str)  }
   | 
 
闭包
new函数
new函数用来分配内存,主要分配值类型,比如int、float32、struct等,返回的是指针
1 2 3 4 5 6 7 8 9 10 11
   | func newDemo() { 	num := 100 	fmt.Printf("num 的类型是%T,值是%v,地址是%v", num, num, &num)      
  	num1 := new(int) 	fmt.Printf("num1 的类型是%T,值是%v,地址是%v", num1, num1, &num1)                      	fmt.Printf("num1 的类型是%T,值是%v,地址是%v,指向的值是%v", num1, num1, &num1, *num1)       }
  |