Go学习
包声明+引入包+函数+变量+语句&表达式+注释
package main
import "fmt"
func main(){
fmt.Println("Hello world")
}
- 必须在源文件非注释的第一行指明这个文件属于拿哪个包
-
package main
定义包名,每个Go应用程序都包含一个名为main的包
-
fmt
实现了格式化的I/O -
/*...*/
和//
是注释 -
Println
和Print('.../n')
一样,输出语法和python类似,Println
后面什么都没有就是直接输出换行
- 如果中间要字符串与数字间隔之类的,类似c++;
- %T可以输出变量的类型
字符串
- 字符串可以通过
+
连接
变量声明
var age int
var aa, bb int32 = 1,2
var a string = "abc"
var c bool = true
var a error // error 是接口
var r io.Reader = strings.NewReader(string("hello, world"))// 在函数调用中可以直接简写
多变量声明
//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
或
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
或
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
或
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
例
package main
var x, y int
var ( // 这种因式分解关键字的写法一般用于声明全局变量
a int
b bool
)
var c, d int = 1, 2
var e, f = 123, "hello"
//这种不带声明格式的只能在函数体中出现
//g, h := 123, "hello"
func main(){
g, h := 123, "hello"
println(x, y, a, b, c, d, e, f, g, h)
}
常量定义
const LENGTH int = 10
const WIDTH int = 5
const (
Unknown = 0
Female = 1
Male = 2
)
iota
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
运行结果为
0 1 2 ha ha 100 100 7 8
常量未定义处的值与上面相同,如果用的是iota就相当于是常量的检索值
简短形式
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。
- 当变量在已经被声明之后,要改变值要用赋值。
-
_
充当抛弃值,和python一样
a 和 b 的类型(int 和 bool)将由编译器自动推断。
g, h := 123, "hello"
运算符
求余用%
,有++
和--
,就是基本运算符和c++差不多
条件语句
和c++一样,不过if后面不一定要带括号
if ... {
}
else if{
}
else{
}
循环
for init;condition;post{
}
和c++差不多,但是中间不能带括号。
如
for i := 0; i <= 10; i++ {
sum += i
}
也可以类似python那样多重枚举
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
- 无限循环
for true {
fmt.Printf("这是无限循环。\n");
}
函数
返回的东西定义在后面,后面的东西可以退出多个,退出多个时用括号+逗号
- 对于形参的每个定义,如果是一样的话可以如下方式,也可以
num1 int,num2 int
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
- 还可以用变量定义函数返回的东西
func deferReturn() (ret int) {
defer func() {
ret++
}()
return 10
}
- 如上,函数返回的东西是ret,然后在defer的时候对ret++,最后函数返回11
数组
var balance [10] float32//直接声明
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}//初始化声明,类似c++的定义,长度不能大于括号内数字
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}//不管长度定义,自动统计大小,定义完长度不变
var r io.Reader = bytes.NewBuffer([]byte("hello, world"))//字符数组
多维
- 类似c++,其他方法如一维
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引为 0 */
{4, 5, 6, 7} , /* 第二行索引为 1 */
{8, 9, 10, 11}, /* 第三行索引为 2 */
}
var threedim [5][10][4]int
向函数传递数组
void myFunction(param [10]int){
}//定义数组大小
void myFunction(param []int)
{
}//不定义数组大小
结构体
type Books struct {
title string
author string
subject string
book_id int
}
- 定义完之后的变量声明
variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
成员访问直接用.
方法
结构体之间的继承
type Student struct {
Human //匿名字段Human
school string
loan float32
}
- 如上,Student的结构体继承了Human结构体的成员和方法,不过这个不叫继承,它通过嵌入字段的方式实现类型之间的组合
方法的实现
type Int int
//这里是对Int这个自定义类型定义了一个方法add
func (i Int) add(a,b int) int{
return a+b
}
//如果想要把计算的结果赋值给i
func(j *Int) add2(a,b int){
*j = Int(a+b)
return
}
值方法与指针方法
type Cat struct {
name string
Animal
}
func (cat *Cat) SetName(name string) {
cat.name = name
}
- 这就是指针方法,这种方法会更改到原值;而值方法就是没有那个星号,不会修改到原值
切片
- 数组不可变,切片可变。切片不用说明长度。
- 可以使用make函数来创建切片
var slice1 []type = make([]type, len)
slice1 := make([]type, len)
- 也可以指定容量,length是初始化长度,capacity为指定容量
make([]T, length, capacity)
- 初始化
s :=[] int {1,2,3 }
- 截取的方法和python中的列表一样
append
numbers = append(numbers, 1)
copy
copy(numbers1,numbers)
语言范围(range)
- range用于迭代数组、切片、通道、集合
如
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
或
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
map(集合)
- 定义
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
如
var a map[string] int
m := map[string]string {
"name":"ccmouse",
"course":"golang",
"site":"imooc",
"quality":"notbad",
}
- 然后加值的时候类似python的方法
- 删除delete
/*删除元素*/ delete(countryCapitalMap, "France")
语言转换
type_name(expression)
如:float32(count)
并发
go 函数名( 参数列表 )
把go放到一个函数前,这样可以让函数以独立的并发线程来执行
通道(channel)
- 用make创建通道
ch1 := make(chan int) // 创建一个整型类型的通道
ch2 := make(chan interface{}) // 创建一个空接口类型的通道, 可以存放任意格式
type Equip struct{ /* 一些字段 */ }
ch2 := make(chan *Equip) // 创建Equip指针类型的通道, 可以存放*Equip
使用通道发送数据
- 使用通道发送和接收数据
发送数据
通道变量<-值
// 创建一个空接口通道
ch := make(chan interface{})
// 将0放入通道中
ch <- 0
// 将hello字符串放入通道中
ch <- "hello"
- 发送将持续阻塞直到数据被接收
package main
func main() {
// 创建一个整型通道
ch := make(chan int)
// 尝试将0通过通道发送
ch <- 0
}
- 由于没有接收,所以报错
fatal error: all goroutines are asleep - deadlock!
接收数据
- 阻塞接收数据
data := <-ch
执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
- 非阻塞接收数据, 非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。
data, ok := <-ch
- data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
- ok:表示是否接收到数据。
defer
- 这是一个延迟执行的语句,放在函数的前面,用于添加函数结束时执行的代码。
func deferReturn() (ret int) {
defer func() {
ret++
}()
return 10
}
- 在return完的时候,对返回的ret++,不过defer的位置要在return之前,如果放在defer之后不会执行,如果是多个defer则会倒序执行(类似栈)
…
- 1、第一个用法主要用于函数有多个不确定参数的情况,可以接受多个不确定量的参数
- 2、第二个用法是切片被打散传入
func test1(args ...string) { //可以接受任意个string参数
for _, v:= range args{
fmt.Println(v)
}
}
func main(){
var strss= []string{
"qwr",
"234",
"yui",
"cvbc",
}
test1(strss...) //切片被打散传入
}
interface
- interface形式上可以定义为一组方法
type Animal interface {
Speak() string
}
- 像这样,都是给一些结构体定义的方法
- 这个例子中Animal类型是一个接口, 定义Animal为任何可以Speak()的东西——所有定义了该方法的类型我们称它实现了
Animal
接口
type Animal interface {
Speak() string
}
type Dog struct {
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct {
}
func (c Cat) Speak() string {
return "Meow!"
}
type Llama struct {
}
func (l Llama) Speak() string {
return "?????"
}
type JavaProgrammer struct {
}
func (j JavaProgrammer) Speak() string {
return "Design patterns!"
}
func main() {
animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}
interface{}
类型
interface{}
类型,空接口。因为所有类型都至少实现了0个方法,所以所有类型都实现了空接口,这就意味着,编写一个函数一interface{}作为参数,可以为函数提供任意值
正则化匹配
- 使用库regexp
regexp.MustCompile
- 提供正则化匹配模型
reg1 := regexp.MustCompile(`/(\d+)%`)
- 其他的就用这个匹配模式匹配就好
flag库
- 用于解析命令行
a = flag.String("name","lili","Input your username")
如果在命令行的时候后给--name=pi
,则a的值就会是pi