跟Java比較學習。
hello word
示例代碼
test1.go文件:
// 包路徑
package main// 導入模塊,下面兩種都行
import ("fmt"
)
import "log"// main方法
func main() {log.Print("hello word !!!")fmt.Print("hello word 222")
}
運行命令
go run .\test1.go
打包二進制
> go build .\test1.go
./test1.exe
變量可見性
首字母大寫就是public
首字母小寫就是private
{不能單獨一行
在Java和C中都可以,go中就不行
正確的應該這樣:
行結束不需要分號;
加上后IDE會自動給刪除
如果你就是要將兩行代碼放在一行,則需要在結尾加上;分號,但IDEA會在保存的時候自動給你拆分為兩行。
字符串
字符串連接+
格式化
// 格式化String.format
value := fmt.Sprintf("%s - %s", ">>", "<<")
// 打印到console上
fmt.Print(value)// 合并:格式化并打印出
fmt.Printf("%s - %s\n", ">>", "<<")
變量
變量申明和賦值
// 只聲明一個變量i
var i int
// 給i變量賦值2
i = 2
// 創建變量并賦值3
ii := 3
// 聲明常量
const pi float64 = 3.14var bo bool = false
bo1 := false
var f1 float32 = 1.1
var f2 = 1.2
f3 := 1.3
普通變量類型
uint8 unsiged int 8位
int8 有符號8位int
int16,int32,int64 類似,沒有long
float32、float64 容易理解,沒有double
這兩個不清楚:
complex64 32 位實數和虛數
complex128 64 位實數和虛數
不一樣的:
uintptr 無符號整型,用于存放一個指針
rune 類似 int32
byte 類似 uint8? 0到255
變量作用域
全局變量和局部變量可以名稱一致,但使用時會優先使用局部變量。
數組
一維數組
var strs = [3]string{"111", "222", "333"}
// 初始化數組中 {} 中的元素個數不能大于 [] 中的數字。 多出就會報錯
var strs = [3]string{"111", "222", "333","444"}
// 只初始化了前兩個元素
var strs = [3]string{"111", "222"}
// 數組長度根據后邊初始化數據的個數來確定為2
var strs = [...]string{"111", "222"}
// 初始化指定元素下表元素的數據
var strs = [...]string{1: "111", 4: "222"}
// 數組的長度
var length int = len(strs)
fmt.Println("數組長度:", length)
for i := 0; i < length; i++ {// 訪問和給數組賦值fmt.Println(len(strs[i]))strs[i] = "ab"
}
二維數組?
// 定義二位數組,并初始化
var rows = [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9},
}
fmt.Println(rows)// 二位數組一行一行添加
// [3][3]int{} 錯誤,行列取悅于append了多少次
var rows1 = [][]int{}
var row1 = []int{1, 2, 3}
var row2 = []int{4, 5, 6}
// 各行可以一樣,也可不一樣長
var row3 = []int{7, 8, 9, 10}
rows1 = append(rows1, row1)
rows1 = append(rows1, row2)
rows1 = append(rows1, row3)
fmt.Println(rows1)
fmt.Println("row count:", len(rows1))
fmt.Println("col count:", len(row1))
fmt.Println("row1 :", rows[0])
fmt.Println("row2 :", rows[1])
// 不允許訪問列 rows[][1] syntax error: unexpected ], expected operand
// fmt.Println("col1 :", rows[][1])
fmt.Println("cell[1][1] :", rows[1][1])// 遍歷二維數組
for i := 0; i < len(rows1); i++ {for j := 0; j < len(rows1[i]); j++ {fmt.Println("cell[", i, "][", j, "] : ", rows1[i][j])}
}
方法參數傳數組和傳指針
// 包路徑
package mainimport "fmt"// main方法
func main() {// 定義二位數組,并初始化var rows = [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9},}fmt.Println(rows)addRow(rows)fmt.Println(rows)// 傳遞二維數組的指針 &rowsaddRow1(&rows)fmt.Println(rows)// 調用固定元素數組參數,必須是固定元素個數數組// 數量不一致直接報錯row1 := [5]int{1, 2, 3, 4, 5}printRow(row1)// 將二維數組的第一行當做一維數組也不行// printRow(rows[0])
}// 數組是值類型,這么傳實際傳的是值而非引用
func addRow(rows [][]int) {row := []int{11, 22}rows = append(rows, row)
}// 接受一個二位數組的指針,就是地址
func addRow1(rows *[][]int) {row := []int{11, 22}*rows = append(*rows, row)
}// 必須這么調用:row1 := [5]int{1, 2, 3, 4, 5}; printRow(row1)
func printRow(row [5]int) {fmt.Println(row)
}
指針數組
// 定義指向數組的指針數組
ptr := []*int{&rows[0], &rows[1], &rows[2]}
指向指針的指針
var pptr **int
已經很熟悉了,不用再說了。
?結構體
基本語法
// 包路徑
package mainimport "fmt"// Book 全局可以使用
type Book struct {title stringauth string
}// main方法
func main() {// 定義結構體,只能在方法里邊用/*type Book struct {title stringauth string}*/var book1 Bookbook1 = Book{"title1", "auth2"}book1 = Book{title: "title2"}// book2 獲取book1的值,最后那個也添加了個逗號,惡心不book2 := Book{title: book1.title,auth: book1.auth,}book1.auth = "1000"// 傳值:不會修改值setAuth200(book2)// 傳地址:會修改值setAuth200Point(&book2)var book3 Book// 沒有book3 == nil 和 book3 == null這么一說// 是空對象相當于java中:book3 = new Book(); 不給里邊賦值,所以直接訪問不報錯fmt.Println(book3)book3.auth = "2000"
}// 真NM耐造,book為null 不會報錯
func setAuth200(book Book) {book.auth = "2000"
}func setAuth200Point(bookPtr *Book) {(*bookPtr).auth = "2000"
}
?繼承和匿名字段
type Person struct {name stringsex stringage int
}func (p *Person) say() {fmt.Println("person fun11")
}type Student struct {// 將Person中的屬性繼承過來 s1.sexPerson// 創建person屬性 s1.person.sexperson Personid intaddr string// 如果出現重名情況age int// 匿名字段string
}// 繼承和匿名字段
func main() {fmt.Println("main ...")s1 := Student{Person{"5lmh", "man", 20}, Person{"5lmh", "man", 20}, 1, "bj", 20, "匿名字段"}fmt.Println(s1)// 獲取person屬性的sex值fmt.Println(s1.person.sex)// 獲取繼承過來的person屬性sexfmt.Println(s1.sex)fmt.Println(s1.Person.sex)// 如果父子類中的屬性重復// 給父類Person中賦值s1.Person.age = 100// 給子類屬性age賦值s1.age = 200fmt.Println(s1)// 繼承還可以繼承方法s1.say()fmt.Println("success ...")
}
切片Slice
類似java的ArrayList?
var arr = []int{1, 2, 3, 4, 5}
fmt.Println(arr)// 切片類似:數組的 substring,前后是包含關系
sp := arr[0:]
fmt.Println(sp)
fmt.Println(len(sp))
fmt.Println(cap(sp))// 使用mark創建
var number = make([]int, 3, 5)
fmt.Println(number, len(number), cap(number))
// 在3個元素后邊添加
number = append(number, 5)
// out: [0 0 0 5] 4 5
fmt.Println(number, len(number), cap(number))
number = append(number, 6)
number = append(number, 7)
number = append(number, 8)
// 長度超過容量后會自動擴容,二倍擴容
number = append(number, 9)
number = append(number, 10)
//out:[0 0 0 5 6 7 8 9 10] 9 10
fmt.Println(number, len(number), cap(number))var number1 = make([]int, len(number)*2, cap(number)*2)
copy(number1, number)
// out:[0 0 0 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0] 18 20
// len內的數據會默認給0
fmt.Println(number1, len(number1), cap(number1))// 將里邊的數據全部清理為0
clear(number1)
// out:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 18 20
fmt.Println(number1, len(number1), cap(number1))
語言范圍Rang
?rang 類似 java中的 迭代器 foreach
數組
// 遍歷數組,index是下標
intArr := []int{1, 2, 3, 4, 5}
for index := range intArr {fmt.Print(index, "=", intArr[index], " ")
}
fmt.Println("")
// 可以直接將value遍歷出來
for index, value := range intArr {fmt.Print(index, "=", value, " ")
}
fmt.Println("")
// 如果不需要index則可以用_替代,否則由會給你報錯,這個變量沒用
for _, value := range intArr {fmt.Print(value, " ")
}
?Map
// map的遍歷
fmt.Println("")
map1 := make(map[int]string, 3)
fmt.Println(map1)
map1[10] = "aa"
map1[11] = "bb"
fmt.Println(map1)
// 遍歷map,當前key和value如果不用,可以用_替代
for key, value := range map1 {fmt.Println(key, ":", value)
}
// 如果只有一個同樣,遍歷的是key,類似數組的index
for key := range map1 {fmt.Println(key)
}
切片?
fmt.Println("")
// 切片也可以類似
spArr := make([]int, 2, 50)
copy(spArr, intArr[3:])
// out:[4 5]
fmt.Println(spArr)
for index := range spArr {fmt.Print(index, "=", intArr[index], " ")
}
channel?
// channel 看樣子類似java中的MQ,但不用那么復雜的實現機制
// chan int : 首先這個是一個通道channel, 然后是一個裝int的channel
// 類似:LinkedQuery<Integer>
ch := make(chan int, 10)
ch <- 11
ch <- 12
ch <- 1000for val := range ch {fmt.Print(val, " ")// 一邊遍歷,一邊可以添加數據,比ArrayList的強多了// 但這么搞就死循環了,邏輯上注意// ch <- 1000
}
// 最后需要關閉
close(ch)
Map集合?
// 創建 <int,string> 初始容量為2
mapCap := 2
map1 := make(map[int]string, mapCap)
fmt.Println(map1)// 添加元素,可相同會覆蓋
map1[11] = "bb"
fmt.Println(map1)
map1[11] = "bbb"
map1[22] = "ccc"
map1[33] = "ddd"
fmt.Println(map1)// 根據Key刪除元素
fmt.Println(len(map1))
delete(map1, 22)
fmt.Println(map1)
fmt.Println(len(map1))// 獲取元素,如果沒有則為空
fmt.Println("key:", 11, ",value:", map1[11])
fmt.Println("key:", 66, ",value:", map1[66])
// 如果有值則 value就是值,hasBollen為true,如果沒有值 hasBollen = false
value, hasBollen := map1[66]
if hasBollen {fmt.Println("數據存在,value:", value)
} else {fmt.Println("數據不存在,key:", 66)
}// 遍歷map
fmt.Println(map1)
for key, value := range map1 {fmt.Println("key:", key, ",value:", value)
}
方法
匿名方法?
func(i int, wg *sync.WaitGroup)為形參
(i, &wg) 為實際參數
var wg sync.WaitGroup
for i := 0; i < 10; i++ {wg.Add(1)go func(i int, wg *sync.WaitGroup) {fmt.Println(i)time.Sleep(20 * time.Microsecond)wg.Done()}(i, &wg)
}
wg.Wait()
接口Interface
不同點:
1. struct 實現 interface,并沒有明顯的實現寫法,各寫各的
2. struct 可以實現部分interface的方法,而不必要全部實現。直接用沒問題,用interface進行引用就報錯:
?
// 包路徑
package mainimport "fmt"// 接口有兩個方法
type Animal interface {call()getName() string
}// 創建類Market,有一個name熟悉
type Market struct {name string
}/**實現方法:1. (m Market): 標識 這個是Market類的方法2. call() 接口的方法
*/
func (m Market) call() {fmt.Println("market call,", "name:", m.name)
}func (m Market) getName() string {return m.name
}type Tiger struct {name string
}func (t Tiger) call() {fmt.Println("tiger call,", "name:", t.name)
}func (t Tiger) getName() string {return t.name
}func animalCall(a Animal) {a.call()
}// 空接口,可以接受任何類型的對象,并根據類型判斷
func print(v interface{}) {switch t := v.(type) {case int:fmt.Println("integer", t)case string:fmt.Println("string", t)}
}// main方法
func main() {// 接口 interfacem1 := Market{name: "m111"}fmt.Println(m1.getName())m1.call()m2 := new(Market)m2.name = "m222"m2.call()t1 := Tiger{name: "t1111"}fmt.Println(t1.getName())t1.call()// 根據傳值的不同animalCall(m1)animalCall(t1)// 定義一個接口,然后復制類對象,按照接口調用就可以var a1 Animala1 = m1a1.call()// 將m1轉換為 Market類型m11 := a1.(Market)fmt.Println(m11.name)// 空接口接受人任何對象print(11)print("str11")}