最近没有继续部署elk系统和学习,是因为有项目进来了,自己需要学多一门语言go,学学吧,多学无害,但最怕学艺不精,最怕样样都懂点,样样都不深~
基础组成
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
package main
import "fmt"
func main() {
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
}
每个Go应用程序都包含一个名为main的包,func main()时候程序开始执行的函数,如果有init()函数则会先执行该函数
注意:{
不能单独
基础语法
- 标记有关键字,标识符,常量,字符串,符合
- go程序中,一行代表一个语句结束。不需要以分号结尾,这些由
go编译器自动完成
- 标识符用来命名变量、类型等程序实体,第一个字符必须是字母或者下划线不能是数字
- 数据类型用于声明函数和变量,他的出现是为了把数据分成所需内存大小不同的数据,节省内存空间
- 声明变量是这样写的
var identifier type
,例如:var xxx string = "XXX"
- 变量声明:①指定变量类型,没有初始化,则变量默认为零值,零值就是系统默认设置的值。字符串的默认类型是空字符串
""
;②根据值自行判定变量类型,var d = true
;③省略var,注意:=
左侧如果没有声明新的变量,就会产生编译错误,var f sring = "X"
可以写成f := "X"
var val int
val := 1 // 编译错误
val, val2 := 1, 2 //没有错,:=是一个声明语句
- 因式分解关键字的写法一般用于声明全局变量
var(
vname1 vtype1
vname2 vtype2
)
- 不带声明格式的只能在函数体中出现
- 常见的如int、float、bool基本类型都是值类型,使用这些类型的变量直接指向在内存中的值,当用=复制的时候,实际上是在内存中将i的值进行了拷贝
- 引用类型,跟c语音的差不多,有指针概念
- 局部变量中声明了变量又没使用到,会报错 a declared and not used
- 如果想交换两个变量的值,可以简单使用
a, b = b, a
,这两个变量的类型必须相同 - 空白标识符_也被用于抛弃值,如值5在
_, b = 5, 7
中被抛弃。_实际上是一个只写变量,不能拿到它的值,go语言中你必须使用所有被声明的变量,但是有时候你并不需要使用从一个函数得到的所有返回值 - 并行赋值,用于一个函数返回多个值时,可以用多个变量受值
常量
- const 常量声明,也可以当做枚举使用。常量可以用函数计算表达式的值,函数萹蓄是内置函数,否则编译错误
const LENGTH = 10
const (
Unknown = 0
Female = 1
Male = 2
)
- iota,特殊常量,可以被编译器修改的常量。第一个iota等于0,每当iota在新的一行中被使用时,他的值都会自动加1,所以a=0,b=1,c=2可以简写如下形式
const (
a = iota
b
c
)
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
运算符
- 算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、其他运算符
- 位运算符:
&
按位与运算符,|
按位或运算符,^
按位异或运算符,<<
左移运算符(乘以2的n次方),>>
右移运算符(除以2的n次方) - 其他运算符,
&
返回变量存储地址,*
指针变量
条件语句
- 特别的是select语句,类似switch,但是他是随机执行一个可运行的case,没有可运行的case,就会阻塞,直到有case可运行
- go没有三目运算符,所以不支持?:形式的条件判断
- switch不用break
- type switch,来判断某个变量实际存储的变量类型
- 使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true
循环语句
- 无特别之处
函数
- 函数定义格式如下
func function_name( [parameter list] ) [return_types] {
函数体
}
例子
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
func max(num1, num2 int) (int, int) {
return num1, num2
}
- 函数参数类型有两种:值传递,引用传递
- 函数定义后可以作为另一个函数的实际参数传入
- 支持匿名函数,可作为闭包。匿名函数是一个“内联”语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明
package main
import "fmt"
func main() {
add_func := add(1,2)
fmt.Println(add_func())
fmt.Println(add_func())
fmt.Println(add_func())
}
// 闭包使用方法
func add(x1, x2 int) func()(int,int) {
i := 0
return func() (int,int){
i++
return i,x1+x2
}
}
结果:
1 3
2 3
3 3
package main
import "fmt"
func main() {
add_func := add(1,2)
fmt.Println(add_func(1,1))
fmt.Println(add_func(0,0))
fmt.Println(add_func(2,2))
}
// 闭包使用方法
func add(x1, x2 int) func(x3 int,x4 int)(int,int,int) {
i := 0
return func(x3 int,x4 int) (int,int,int){
i++
return i,x1+x2,x3+x4
}
}
结果:
1 3 2
2 3 0
3 3 4
变量作用域
- pointer的初始化默认值nil
数组
- 无特别
指针
- 取地址符
&
,放到一个变量前使用就会返回相应变量的内存地址 - nil空指针,一个指针通常缩写为ptr
结构体
- 结构体定义需要使用type和struct语句。struct语句定义一个新的数据类型
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
}
- 访问结构体成员,用点号
.
操作符,格式为:结构体.成员名 - struct类似于java中的类
切片(Slice)
- go数组的长度不可改变,go提供了一种灵活,功能强悍的内置类型切片(“动态数组”)。切片不需要说明长度
var identifier []type
或者用make()函数来创建切片
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
范围(Range)
- Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对
Map(集合)
- 无
递归函数
- 无
类型转换
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %f\n",mean)
}
接口
- 无
错误处理
package main
import (
"fmt"
)
// 定义一个 DivideError 结构
type DivideError struct {
dividee int
divider int
}
// 实现 `error` 接口
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// 正常情况
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// 当被除数为零的时候会返回错误信息
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}
执行以上程序,输出结果为:
100/10 = 10
errorMsg is:
Cannot proceed, the divider is zero.
dividee: 100
divider: 0
并发
- 支持并发,只需要通过go关键字来开启goroutine即可,goroutine 是轻量级线程
- 所有的goroutine共享一个地址空间
- 通道channel是用传递数据的一个数据结构,通道可用于两个goroutine之间通过传递一个指定类型的值来同步运行和通讯
ch <- v // 把 v 发送到通道 ch
v := <-ch // 从 ch 接收数据
// 并把值赋给 v
PS:
1、欢迎访问我的个人站点:小白求学进阶
2、欢迎访问我的CSDN博客:小白求学进阶
3、微信公众号:
4、本文为原创文章,转载还需告知本人~谢谢