跟Java比较学习。
hello word
示例代码
Go
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会在保存的时候自动给你拆分为两行。
字符串
字符串连接+
格式化
Go
// 格式化String.format
value := fmt.Sprintf("%s - %s", ">>", "<<")
// 打印到console上
fmt.Print(value)
// 合并:格式化并打印出
fmt.Printf("%s - %s\n", ">>", "<<")
变量
变量申明和赋值
Go
// 只声明一个变量i
var i int
// 给i变量赋值2
i = 2
// 创建变量并赋值3
ii := 3
// 声明常量
const pi float64 = 3.14
var 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
变量作用域
全局变量和局部变量可以名称一致,但使用时会优先使用局部变量。
数组
一维数组
Go
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"
}
二维数组
Go
// 定义二位数组,并初始化
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])
}
}
方法参数传数组和传指针
Go
// 包路径
package main
import "fmt"
// main方法
func main() {
// 定义二位数组,并初始化
var rows = [][]int{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9},
}
fmt.Println(rows)
addRow(rows)
fmt.Println(rows)
// 传递二维数组的指针 &rows
addRow1(&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)
}
指针数组
Go
// 定义指向数组的指针数组
ptr := []*int{&rows[0], &rows[1], &rows[2]}
指向指针的指针
Go
var pptr **int
已经很熟悉了,不用再说了。
结构体
基本语法
Go
// 包路径
package main
import "fmt"
// Book 全局可以使用
type Book struct {
title string
auth string
}
// main方法
func main() {
// 定义结构体,只能在方法里边用
/*type Book struct {
title string
auth string
}*/
var book1 Book
book1 = 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"
}
继承和匿名字段
Go
type Person struct {
name string
sex string
age int
}
func (p *Person) say() {
fmt.Println("person fun11")
}
type Student struct {
// 将Person中的属性继承过来 s1.sex
Person
// 创建person属性 s1.person.sex
person Person
id int
addr 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属性sex
fmt.Println(s1.sex)
fmt.Println(s1.Person.sex)
// 如果父子类中的属性重复
// 给父类Person中赋值
s1.Person.age = 100
// 给子类属性age赋值
s1.age = 200
fmt.Println(s1)
// 继承还可以继承方法
s1.say()
fmt.Println("success ...")
}
切片Slice
类似java的ArrayList
Go
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
数组
Go
// 遍历数组,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
Go
// 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)
}
切片
Go
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
Go
// channel 看样子类似java中的MQ,但不用那么复杂的实现机制
// chan int : 首先这个是一个通道channel, 然后是一个装int的channel
// 类似:LinkedQuery<Integer>
ch := make(chan int, 10)
ch <- 11
ch <- 12
ch <- 1000
for val := range ch {
fmt.Print(val, " ")
// 一边遍历,一边可以添加数据,比ArrayList的强多了
// 但这么搞就死循环了,逻辑上注意
// ch <- 1000
}
// 最后需要关闭
close(ch)
Map集合
Go
// 创建 <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)
}
方法
匿名方法
Go
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
不同点:
-
struct 实现 interface,并没有明显的实现写法,各写各的
-
struct 可以实现部分interface的方法,而不必要全部实现。直接用没问题,用interface进行引用就报错:
Go
// 包路径
package main
import "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() {
// 接口 interface
m1 := 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 Animal
a1 = m1
a1.call()
// 将m1转换为 Market类型
m11 := a1.(Market)
fmt.Println(m11.name)
// 空接口接受人任何对象
print(11)
print("str11")
}