开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
“基础不牢,地动山摇” 。新接触一门编程语言,基础语法是必须得学扎实了。
前言
今天快速过一遍Go基础语法,先对Go有个简单认识。
主要内容:代码基本结构、变量、常量、数据类型、运算符、流程控制。
下面正式开始每一个知识点的学习吧
1.代码基本结构
学习任何一门编程语言,以经典案例打印 “Hello World”为开始
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
简单的一个例子,对代码基本结构先有所认识
- package:声明包名
- import:导入标准库或第三方库
- func:定义函数或方法,注意main函数只能在main下面
- 其他:变量、常量,得在哪声明和怎么声明呢,那就接着往下学
2.变量
声明
- 标准声明:
var name string或var name = "haha"(后面的类型可省略,go会自动做类型推导) - 批量声明:
var name, address string或var (name string; age int)用括号,里边分号可替换为回车多行写 - 简短声明:
name := "haha",使用**:=**,注意这种写法只能在函数内使用
package main
import "fmt"
func main() {
var name string
var (
name2 string
age int
)
name3 := "haha"
fmt.Println(name, name2, age, name3)
}
初始化
- 自动初始化:变量声明后为对应类型零值(int 为 0,float 为 0.0,bool 为 false,string 为空字符串,指针为 nil)
- 手动初始化:
var name string = "haha"或name, age := "haha", 18
作用域
- 全局变量:在函数体外的定义,作用域整个包,甚至在被外部包import后也可使用(注意大写首字母)
- 局部变量:在函数体内的定义,只能在函数内使用。和全局变量重名时,函数体内局部变量会覆盖掉全局变量,但函数执行完后,全局变量会自动恢复
匿名变量
- 使用下划线
_表示,用于忽略某个值,例如val, _ := foo(),忽略error; - 匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明
3.常量
声明和初始化
- 单行:
const a = 1或const a, b = 1, 2 - 多行:
const(a=1; b=2)使用括号,里边分号可替换为回车
package main
import "fmt"
func main() {
const a = 111
const (
b = 222
c = 333
)
fmt.Println(a, b, c)
}
注意点
- 数据类型范围:只能是布尔型、数字型(整数型、浮点型和复数)和字符串型,这些标量类型
- 常量的值必须是能够在编译时就能够确定的,所以是全局有效
iota
常量计数器,只能在常量表达式中使用。出现时先被重置为0。const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用
//简单例子
const (
n1 = iota
n2
n3
n4
)
fmt.Println(n1, n2, n3, n4) //0 1 2 3
//注意下面两个例子的区别
const (
n1 = iota
n2 = 100
n3 = iota
n4
)
fmt.Println(n1, n2, n3, n4) //0 100 2 3 (说明:n3被iota重新赋值,行索引为2,然后下面继续自增)
const (
n1 = iota
n2 = 100
n3
n4
)
fmt.Println(n1, n2, n3, n4) //0 100 100 100(说明:n3没被重新赋值,则下面的所有值和上一行值相同)
4.数据类型
基本类型
- 整型:有符号int、int8、int64、int32、int64;无符号uint、uint8、uint64、uint32、uint64、uintptr
- 浮点型:float32、float64、complex32、complex64
- 布尔型:true、false(无法参与数值运算,也无法与其他类型进行转换)
- 字符串:string,使用双引号,支持转义字符 \n \r \t
- 字符:byte(uint8别名)、rune(int32别名),使用单引号
复合类型
array、slice、map、struct、channel、func、interface
指针类型
pointer:例如*int *string *float32 等等
自定义类型
使用type关键字定义(go类型系统强大之处)
类型转换
go没有隐式类型转换,只能强类型转换,并且两个类型要支持相互转换才能使用
语法:T(表达式)。例子:
func main() {
a := 10
b := float32(a)
fmt.Println(fmt.Sprintf("%T", b), b) //float32 10
}
也可以使用strconv库:支持string类型和其他多个类型的相互转换
5.运算符
常规
- 算术运算符:+ - * / %(注意,自增++、自减—,是单独语句,不是运算符)
- 关系运算符:== ≠ > ≥ < ≤
- 逻辑运算符:&& || !
- 位运算符:二进制位操作,包括 & | ^
<<>> - 赋值运算符:= += -+ *= /= %=
<<=>>=&= |= ^=
其中,<<左移、>>右移,代码示例:
fmt.Println(1 << 3) //8 规则:2的3次方*1
fmt.Println(2 << 3) //16 规则:2的3次方*2
fmt.Println(2 >> 3) //0 规则:2除以2的3次方
fmt.Println(16 >> 3) //2 规则:16除以2的3次方
幂运算:使用math库
fmt.Println(math.Pow(2, 4)) //16 含义:2的4次方
fmt.Println(math.Pow10(2)) //100 含义:10的2次方
6.流程控制
分支结构
if else :条件语句不用加括号,多分支选择,并且支持特殊写法
//一层
a := 10
if a > 0 {
fmt.Println("111")
}
//两层
a := 10
if a > 0 {
fmt.Println("111")
} else {
fmt.Println("222")
}
//三层
a := 10
if a > 0 {
fmt.Println("111")
} else if a > -10 {
fmt.Println("333")
} else {
fmt.Println("222")
}
//特殊写法(注意a成为只作用于if内的局部变量)
if a := 10; a > 0 {
fmt.Println("111")
}
switch case:不需要用break,因为不会自动贯穿,若需要贯穿得用fallthrough;支持单值、多值以及表达式
//常规写法,单个值
finger := 2
switch finger {
case 1:
fmt.Println("111")
case 2:
fmt.Println("222")
default:
fmt.Println("333")
}
//一个分支多个值
switch n := 7; n {
case 1, 3, 5, 7, 9:
fmt.Println("奇数")
case 2, 4, 6, 8:
fmt.Println("偶数")
default:
fmt.Println(n)
}
//分支还可以是表达式
age := 30
switch {
case age < 25:
fmt.Println("好好学习吧")
case age > 25 && age < 35:
fmt.Println("好好工作吧")
case age > 60:
fmt.Println("好好享受吧")
default:
fmt.Println("活着真好")
}
//fallthrough贯穿到下一个分支
s := "a"
switch {
case s == "a":
fmt.Println("a")
fallthrough
case s == "b":
fmt.Println("b")
case s == "c":
fmt.Println("c")
default:
fmt.Println("...")
}
//输出a b
循环结构
for :go没有while和do..while,用for统一替代,用法非常灵活多变
for 初始语句;条件表达式;结束语句{
循环体语句
}
//常规写法
for i := 0; i < 10; i++ {
fmt.Println(i)
}
//替代掉while(i<10)语句,可模拟do..while
i := 0
for i < 10 {
fmt.Println(i)
i++
}
//替代掉while(true)语句
for {
循环体语句
}
for range:键值循环遍历数组、切片、字符串、map 及通道(channel)
规律:
- 数组、切片、字符串返回索引和值;
- map返回键和值;
- 通道(channel)只返回通道内的值;
names := []string{"zhangsan", "lisi", "王五"}
for k, v := range names {
fmt.Println(k, v)
}
//输出:
//0 zhangsan
//1 lisi
//2 王五
其他关键字
goto:跳转到指定标签,慎用,可忽略
break:跳出循环,作用于for switch select
continue:继续下一次循环
总结
对代码基本结构先有所认识,然后对变量常量的声明与初始化多种方式、数据类型、运算符、以及流程控制中的分支结构与循环结构多种用法,都有所学习。
如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!