目录
一、变量相关基础语法
1、变量的定义以及赋值
2、变量的交换
3、匿名变量
4、变量的作用域
二、常量
三、基本数据类型
1、常见数据类型
2、数据类型的转换
四、运算符
五、函数
函数高级用法
函数也是一个类型
函数也是一个变量,也可以赋值
高阶、匿名函数
根据go语言数据类型特点,可以将一个函数作为另外一个函数的参数
闭包
六、基本语法
一、变量相关基础语法
1、变量的定义以及赋值
var name type
- var 是声明变量关键字,可省略
- name是变量名
- type是变量类型
形式1(只定义不赋值)
var {
name string
age int
}
形式2 (同时定义多个相同类型的变量)
var a,b,c int = 1,1,1
形式3 (简单写法,省略var关键字)
name := "XXX"
age := 18
打印变量类型
fmt.Printf("%T,%T",name,age)
打印内存地址
fmt.Printf("%p",&name)
当一个变量被声明之后,如果没有显示的给他赋值,系统会自动赋予该类型零值
- 整形和浮点数默认值为0和0.0
- 字符串默认值为空字符串
- 布尔类型默认为false
- 切片、函数、指针默认为nil
2、变量的交换
var a int = 100
var b int = 200
a, b = b, a
3、匿名变量
匿名变量为一个下划线"_",任何赋值给这个标识符的值都将被抛弃,因为这些值不能再以后的代码中使用
package main
import "fmt"
func main() {
test2()
}
func test() (int, int) {
return 10, 20
}
func test2() {
a, b := test()
fmt.Println(a, b) // 10,20
// 其中第二个返回值用_接受,将不会再被使用
c, _ := test()
fmt.Println(c) // 30
}
#输出
10 20
10
匿名变量不会占用内存空间,不会分配内存,匿名变量之间也不会因为多次声明而无法使用
4、变量的作用域
(1)局部变量
在函数体内声明的变量称之为局部变量,它们的作用域在函数体内,函数的参数和返回值变量都属于局部变量
(2)全局变量
在函数体外声明的变量称之为全局变量,全局变量只要在一个源文件中定义,就可以在所有源文件中使用,全局变量声明必须以var关键字开头。GO语言中全局变量和局部变量名称可以相同,但是函数体内的局部变量会优先考虑,遵循就近原则
func main() {
var temp int = 100
if true {
temp := 50
fmt.Println(temp) // 50
}
fmt.Println(temp) // 100
}
二、常量
常量可以是任何数据类型,一旦定义将无法被改变
const identifier [type] = value
- 显示类型定义:const b string = "abc"
- 隐式类型定义:const b = "abc"
- 多个常量定义的声明可以简写为 const a, b = 3.14, "lb"
iota,特殊常量,iota是go语言的常量计数器,iota在const关键字出现时将被重置为0(const内部的第一行),const中每新增一行常量声明将使iota计数一次(iota可以理解为const语句块中的行数索引)
const (
a = iota // 输出0
b // 输出1
c // 输出2
d = "haha" // 输出haha iota 3
e // 输出haha iota 4
f = iota // 输出5
g // 输出6
)
iota常用于作枚举值
三、基本数据类型
1、常见数据类型
布尔类型
bool
整数型
有符号:
int8,int32,int64(默认)
无符号(大于等于0的值):
uint8,uint16,uint32,uint64
浮点型
float32,float64(默认64,默认保留6位小数)
float32小数点有效数字位数为6位
float64小数点有效数字位数为14位
尽量采用float64计算避免精度缺失
字符串
string
2、数据类型的转换
Go语言中不存在隐式类型转换,因此所有的类型转换必须显示的声明 ,高类型向低类型转换会存在精度缺失
a := 3 // int
b := 5.0 // float64
c := float64(a) // 将a转为float64
d := int(b) // int
四、运算符
算术运算符、位运算符、逻辑运算符等 和其他语言一致
五、函数
格式如下
func function_name([parameter list]) [return_types] {
}
func main() {
test()
test2("a")
test3("b", 1)
c := test4("c")
d, e := test5("d", "e")
fmt.Println(c)
fmt.Println(d, e)
test6(1,2,3)
}
// 无参无返回值函数
func test() {
fmt.Println("无参无返回值函数")
}
// 有一个参数的函数
func test2(str string) {
fmt.Println("有一个参数的函数" + str)
}
// 有两个参数的函数
func test3(str string, a int) {
fmt.Printf("有一个参数的函数%s,%d\n", str, a)
}
// 有一个返回值的函数
func test4(str string) string {
return str + "test4"
}
// 有多个返回值的函数
func test5(x, y string) (string, string) {
return y, x
}
// 可变参数
func test6(num ...int) {
sum := 0
for i := 0; i < len(num); i++ {
sum += num[i]
}
fmt.Println(num[i])
}
#输出
无参无返回值函数
有一个参数的函数a
有一个参数的函数b,1
ctest4
e d
6
- 值类型的数据:操作的是数据本身 int、string、bool、float、array、struct
- 引用类型数据:操作的是数据的地址 指针,slice、map,chan管道, interface接口
其中array是固定长度数组,值类型,slice是可变长度数组,引用类型
array定义方式:
[4]int{1,2,3,4}
slice定义方式:
[]int{1,2,3,4}
函数高级用法
-
函数也是一个类型
func main() {
// fu如果不加括号,函数就是一个变量,如果加了括号就变成函数的调用
fmt.Printf("%T", fu) // func()
}
func fu() {
}
#输出
func()
func main() {
// fu如果不加括号,函数就是一个变量,如果加了括号就变成函数的调用
fmt.Printf("%T", fu) // func(int, int)
}
func fu(a, b int) {
}
#输出
func(int, int)
-
函数也是一个变量,也可以赋值
func main() {
var fu2 func() int
fu2 = fu
fmt.Println("fu2=", fu2())
fu3 := fu
fmt.Println("fu3=", fu3())
}
func fu() int {
return 1
}
#输出
fu2=1
fu3=1
-
高阶、匿名函数
根据go语言数据类型特点,可以将一个函数作为另外一个函数的参数
fun1()、fun2() 将fun1()函数作为fun2()函数的参数,其中
fun2()函数叫做高阶函数
fun1()函数叫做回调函数
// 函数式编程
func main() {
r1 := oper(1, 2, add)
fmt.Println(r1)
r2 := oper(1, 2, sub)
fmt.Println(r2)
r3 := oper(2, 1, func(a, b int) int {
if b == 0 {
fmt.Println("除数不能为0")
return 0
}
return a / b
})
fmt.Println(r3)
}
func oper(a, b int, fu func(a, b int) int) int {
res := fu(a, b)
return res
}
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
-
闭包
闭包通常是指一个函数中引用了函数外部的变量,这样的函数就形成了一个闭包。闭包可以访问其外部函数的变量,甚至可以修改这些变量的值。在闭包中,变量的生命周期可以得到延长,因为它们被引用了,所以在闭包中仍然存在
func main() {
x := 10
f := func() {
fmt.Println(x)
}
f() // 输出 10
x = 20
f() // 输出 20
}
在上述代码中,我们定义了一个闭包 f ,它引用了函数外部的变量 x 。在调用 f() 时,它会输出 x 的值,因为闭包中引用的变量 x 实际上是指向函数外部的变量 x 。在之后修改了 x 的值之后,再次调用 f() 时,它会输出新的 x 的值。这就是闭包的一个典型应用场景。
func main() {
f1 := increment()
fmt.Println("f1=", f1())
fmt.Println("f1=", f1())
fmt.Println("f1=", f1())
f2 := increment()
fmt.Println("f2=", f2())
fmt.Println("f2=", f2())
fmt.Println("f2=", f2())
fmt.Println("f1=", f1())
fmt.Println("f1=", f1())
fmt.Println("f1=", f1())
}
/*
*
定义了一个返回值为匿名函数的函数
*/
func increment() func() int {
i := 0
fun := func() int {
i++
return i
}
return fun
}
#输出
f1= 1
f1= 2
f1= 3
f2= 1
f2= 2
f2= 3
f1= 4
f1= 5
f1= 6
六、基本语法
1、输入输出fmt
fmt.Println() // 打印并换行
fmt.Printf() // 格式化输出
fmt.Print() // 打印并输出
var x int
var y float64
fmt.Scanln(&x,&y) // 接受输入
2、if语句
if a == b {
}
无中括号
3、switch语句
var int = x
switch var {
case var1:
case var2:
case var3,var4:
default:
}
break关键字可省略,只会匹配其中一个case
fallthrough关键字,可让原本不满足case条件的依然得到执行
a := false
switch a {
case false:
fmt.Println("false")
fallthrough //cas穿透,不管下一个条件满不满足,都会执行
case true:
fmt.Println("true")
}
# 同时输出false和true
如果不需要穿透也可以使用break
a := 1
switch a {
case 1:
fmt.Println("1")
fallthrough //cas穿透,不管下一个条件满不满足,都会执行
case 2:
if a == 1 {
break
}
fmt.Println("2")
case 3:
fmt.Println("3")
}
# 只会输出1
4、for语句
// 方式1
for i := 1; i <= 10; i++ {
}
// 方式3
i := 1
for i <= 10 {
i++
}
// 无限循环
for {
i++
}
无中括号,无while语句、也可在for中使用continue,break等关键字和其他语言一致
类似java中foreach的语法
str := "abc"
for i, v := range str {
fmt.Print(i) // 打印索引
fmt.Printf("%c", v) // 打印具体值 %c是转换为字符,如果没有%c默认是打印ASCII值
}
#输出 0a1b2c
// 编译报错 string 是不能修改的
str[0] = 'd'