变量、常量和枚举
内建变量类型
内建变量类型有:
- bool、string
- (u)int、(u)int8、(u)int16、(u)int32、(u)int64、 uintptr(指针)
- byte、rune(相当char,但是是32bit即4字节)
- float32、 float64、complex64(复数,实部为32bit,虚部为32bit)、complex128(复数,实部为64bit,虚部为64bit)
变量的定义和初始化
- 第一种:只定义变量未初始化
- 在Golang中未初始化的变量(包内部变量和函数内变量)都有默认值,可以只定义就使用。
- 下列代码中定义变量a,s。输出结果分别为0和空字符串
func variableZeroValue(){
// 定义变量,初始化,合理的初始值
// 在C中未初始化的局部变量(自动变量)初始值随机分配,不确定的,而全局变量 、静态变量初始值为0
// 在java中未初始化的成员变量有默认值,而局部变量没有默认值
var a int
var s string
fmt.Print(a, s)
fmt.Printf("\n%d %q\n", a, s)
}
注
Println 打印的每一项之间都会有空格,Print 没有
Println 会自动换行,Print 不会
Printf 是格式化输出,需要占位符
- 第二种:变量常规的定义和初始化
- 通常定义变量的格式是 var 变量名 变量类型 = 变量值
- Go语言中的函数内变量必须被使用,否则会报错
- Go语言中的包内部变量可以仅仅定义和初始化,但不去使用它
func variableInitialValue(){
// 变量初始化
var a, b int = 3, 4
var s string = "Helle Go"
fmt.Println(a, b, s)
}
注
包内变量是指定义和初始化在函数外,在包内的变量。其作用域在整个包内;
函数内变量是指定义和初始化在函数内的变量,作用域在函数内,不能作用在整个包内。
- 第三种:省略变量类型的定义和初始化
- 省略变量定义类型,由计算机自动判断识别。这种情况下必须对变量初始化。
func variableTypeDeduction(){
// 省略变量定义类型,由计算机自动判断识别
var a, b, c, s = 3, 4, true, "def"
fmt.Println(a, b, c, s)
}
- 第四种:省略var和变量类型的定义和初始化
- 此方法是对变量定义和初始化时使用**:=**来操作的;
- 不能对包内变量定义和初始化。
func variableShorter(){
// 简单写法
// 变量在定义时初始化即第一次对变量进行操作时用:=,这里省略关键词var
// :=仅仅在函数内使用,在定义包内部变量时不能使用
a, b, c, s := 3, 4, true, "shorter"
// 第二次对变量进行操作时,就能不使用:=
b = 5
fmt.Println(a, b, c, s)
}
注
变量可以使用变量组来减少写var关键字,如下列代码
var (
bb = 4
gg = "Hello Go"
)
// 等效于
var bb int = 4
var gg string = "Hello Go"
数据类型之复数
- complex64(复数,实部为32bit,虚部为32bit),complex128(复数,实部为64bit,虚部为64bit)
- 使用欧拉公式进行举例,输出结果是实部为0,虚部是接近为0的浮点数;
func euler(){
//c := 3 + 4i
//// 取模
//fmt.Println(cmplx.Abs(c))
//使用1i表示虚部i。如果直接使用i的话,会被认为变量i而非虚部i。
//欧拉公式 表示方法一
fmt.Println(
cmplx.Pow(math.E, 1i * math.Pi) + 1)
//欧拉公式 表示方法二
fmt.Println(
cmplx.Exp(1i * math.Pi) + 1)
}
类型转化
- Go语言中类型转化只有强制的,当数据类型不匹配时必须写明转化的类型;
- 在C/C++等语言中除了强制类型转化之外,还有隐式类型转化即可以不写明类型转化,例如
int main()
{
int a = 5;
float b = 3;
printf("%f",a*b);
}
- a可以向上转型为float类型
- Go语言中强制类型转化的例子:
func triangle(){
var a, b int = 3, 4
var c int
c = int(math.Sqrt(float64(a * a + b * b)))
fmt.Println(c)
}
常量
- 常量的作用相当于是文本替换的作用;
func consts(){
//// 常量的作用相当于是文本替换的作用
//const filename = "Goland.txt"
//const a, b = 3, 4
//// 这里若将a,b定义数据类型,则下面在Sqrt中需要进行强制类型转化为float64
//// 常量const数值可以作为各种类型使用
const ( //常量可以定义在一组中
filename = "Goland.txt"
a, b = 3, 4
)
var c int
c = int(math.Sqrt(a * a + b * b))
fmt.Println(filename, c)
}
特殊的常量-枚举
- 对枚举中的每个元素赋值。
- 下列代码输出结果是0 1 2 3
const(
cpp = 0
java = 1
python = 2
goland = 3
)
fmt.Println(cpp, java, python, goland)
- 对枚举的第一个元素赋值,并且元素可以自增
- 使用iota给第一个元素赋值,能实现后面的元素在前一个元素的基础上自增一;
- iota是从0开始自增的
- 下列代码输出结果是
10 14 12 13
1 1024 1048576 1073741824 1099511627776 1125899906842624
const (
cpp = iota + 10
_
python
goland
javascript
)
fmt.Println(cpp, javascript, python, goland)
// 输出结果是常量自增,不需要每个赋值
// b, kb, mb, gb, tb, pb
const (
b = 1 << (10 * iota) //左移动10位,即扩大1024倍
kb
mb
gb
tb
pb
)
fmt.Println(b, kb, mb, gb, tb, pb)
- 对枚举中的第一个元素赋值。
- 下列代码输出结果是97 97 97。没有自增。
const (
aa = 97
bb
cc
)
fmt.Println(aa, bb, cc)
条件与循环语句
条件语句
- 条件语句if的格式是
if 条件 {
} else if 条件{
} else {
}
- if语句的案例
const filename = "Golang.txt"
//contents, err := ioutil.ReadFile(filename) // 读取文件,访问文件内容byte数组和出错信息
//if err != nil {
// fmt.Println(err)
//} else {
// fmt.Printf("%s\n", contents)
//}
if contents, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
}else {
fmt.Printf("%s\n", contents)
}
// if外不能使用变量contents
// fmt.Printf("%s\n", contents) 这里contents会报错,contents生存期在if中,在if外不能使用contents
- if的条件里可以赋值
- if的条件里赋值的变量作用域就在这个if语句里
- 条件语句switch casei的格式是
switch 表达式 {
case 表达式一:
语句一
case 表达式二:
语句二
...
default:
}
-
Goland中switch会自动break,除非使用fallthrough;
-
switch通常执行一个case后会立即退出swithc,case后的fallthrough语句表明执行完当前 case 语句之后按顺序执行下一个case 语句;
-
swithc后可以不跟表达式,相当与switch true,将case中的表达式与true比较,相等执行;
-
多个有相同值的 case 是不允许的;
-
case后的表达式可以有多个,用逗号分隔。
-
switch语句案例
func grade(score int) string {
g := ""
switch {
case score < 0 || score > 100:
panic(fmt.Sprintf(
"Wrong score: %d", score))
case score < 60:
g = "E"
case score < 70:
g = "D"
case score < 80:
g = "C"
case score < 90:
g = "B"
case score <= 100:
g = "A"
}
return g
}
循环语句
循环语句for的格式
for 初始条件; 结束条件; 递增表达式 {
}
// 例
sum := 0
for i := i; i <= 100; i++ {
sum += i
}
- for的条件不需要括号
- for的条件里可以省略初始条件、结束条件、递增表达式
- 省略初始条件和递增表达式,相当于while
- for什么都省略,相当于无限循环
// 十进制转二进制案例
func convertToBin(n int) string{
result := ""
for ; n > 0; n /= 2 {
lsb := n % 2 // 取模
result = strconv.Itoa(lsb) + result
}
return result
}
条件语句和循环语句要点回顾
- for, if后面的条件没有括号;
- if条件里可以定义变量;
- 没有while;
- switch不需要break,也可以直接switch多个条件。
函数
- 函数名在前,类型在后
- 函数可以返回对个值
- 函数返回多个值时可以对他们取名字,仅用于非常简单的函数
- 函数内还可以嵌套函数,即函数可以作为参数
- 可变参数列表,同数组一样使用
- 没有默认参数,可选参数,函数重载等操作
函数的案例
func eval(a, b int, op string) (int, error) {
switch op {
case "+":
return a + b, nil
case "-":
return a - b, nil
case "*":
return a * b, nil
case "/":
//return a / b
q, _ := div(a, b) // go中定义的变量必须使用,这里使用_表明第二个字段r不想被定义出来
return q, nil
default:
return 0, fmt.Errorf("unsupported operation: %s" + op)
}
}
// 带余数除法 13 / 3 = 4 ... 1
//func div(a, b int) (int, int){
// return a / b, a % b
//}
func div(a, b int) (q, r int){
//q = a / b
//r = a % b
//return q, r
return a / b, a % b
}
// 函数式编程
func apple(op func(int, int) int, a, b int) int {
p := reflect.ValueOf(op).Pointer() //反射,获取指针
opName := runtime.FuncForPC(p).Name() //获得操作的名字,通过函数名执行对应的函数
fmt.Println("Calling function %s with args " + "(%d, %d)\n", opName, a, b)
return op(a, b)
}
func pow(a, b int) int {
return int(math.Pow(float64(a), float64(b)))
}
// 可变参数列表
func sum(numbers ...int) int {
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
func main(){
fmt.Println(
eval(3, 4, "*"),
)
// 多返回值的函数
fmt.Println(
div(13, 3),
)
q, r := div(13, 3)
fmt.Println(q, r)
// 带error返回值的函数
if result, err := eval(9,4, "/"); err != nil {
fmt.Println("Error", err)
} else {
fmt.Println(result)
}
// 函数式编程一
fmt.Println(apple(pow, 3, 4))
// 函数式编程二 通过匿名函数来实现的
fmt.Println(apple(
func(a int, b int) int {
return int(math.Pow(
float64(a), float64(b)))
}, 3, 4),
)
// 可变参数列表的案例
fmt.Println(sum(1, 2, 3, 4, 5))
}
指针
- Go中指针不能运算,即指针不能++或–等操作;
- Go语言中只用值传递一种方式;
- Go中实现引用传递需要借助指针;
指针的定义和赋值
var a int = 2
var pa *int = &a // pa指向变量a的位置
*pa = 3 // a的值为3
fmt.Println(a) // 3
注
值传递:将变量值拷贝一份传递给函数,在函数中无论对值传递参数怎么操作,多不会影响原来的变量;
引用传递:将变量的地址传递给函数,在函数中可以对原变量进行操作;
在java和python中除了内建类型外,自定义的函数参数一般都是应用传递。
实现引用传递案例
func swap(a, b *int) {
*b, *a = *a, *b // 将a指向的内容和b指向的内容进行交换
}
func main() {
a, b := 3, 4
swap(&a, &b) // 取a,b的地址
fmt.Println(a, b)
}
基础语法就此结束
本文深入讲解Go语言的基础语法,包括变量、常量、枚举的定义与初始化,复数类型,类型转换,条件与循环语句,以及函数和指针的使用。通过实例演示Go语言的特性与最佳实践。

1045

被折叠的 条评论
为什么被折叠?



