第二章 Go基础语法
作者:互联网
第二章 Go基础语法
2.1 变量定义
创建变量方式(定义变量可不赋初值也可赋初值):
- 不赋初值
- 整型:
var a int
,默认为0 - 字符串:
var s string
,默认值无用println()
法打印,但用printf("%q")
打印出空字符串“”
,&q
指的是quotation
- 赋初值
- 整型:
var a int = 3
,var b,c int = 1,2
- 字符串:
var s sring = "abc"
Go语言很严格,只要是定义了的变量一定要用到,不然会报错
- 创建变量时省略变量类型
Go语言可以省略变量类型直接赋值,编译器会自动识别变量的类型,如:
- `var a,b = 3,4``
- ``var s = "abc"`
- 甚至可以不同的类型混合定义
var a,b,c,d = 3,4,true,"abc"
- 更短的创建变量的方法
- 去掉
var
,再在” = “前面加“ : “,即a := 2
,这样与var a = 2
是一样的,但这种用法仅限于函数内 - 还可以用
var(a = 3 c = 4 d = true)
括号的形式一次性定义多个变量,来避免多次写var
- 关于函数外面的变量声明
- 在函数外面也可以定义变量,但不可以用“ : ”来定义变量
- 函数外面的语句开头必须有
var
或者func
Go语言没有全局变量的说法,函数外面的变量是包内部的变量,作用域仅限于包内部
package main
import "fmt"
//在函数外面也可以定义变量,但不可以用:来定义变量
//函数外面的语句开头必须有var或者func
var aa = 2
var ss = "kk"
//bb := true//函数外面不可用:来定义变量
var (
cc = 4
gg = true
hh = "anc"
)//还可以用括号的形式一次性定义多个变量,避免重复写var
func variableZeroValue() {
var a int
var s string
fmt.Println(a, s)//0
fmt.Printf("%d %q \n", a, s)//0 “”
}
func variableInitialValue() {
var a int = 3
//var b, c int = 1, 2//Go语言很严格,只要是定义了的变量一定要用到,不然会报错
var s string = "abc"
fmt.Println(a, s) //3 abc
}
func variableTypeDeduction() {
var a, b, c, d = 3, 4, true, "abc"
fmt.Println(a, b, c, d)//3 4 true abc
}
func variableShorter() {
a, b, c, d := 3, 4, true, "abc" //将var去掉,在=前面加:,这样跟var a, b, c, d = 3, 4, true, "abc"是一样的
b = 5 //第二次赋值变量就不能加:了,就像已经var过的变量第二次赋值就不加var一样
fmt.Println(a, b, c, d) //3 5 true abc
}
func main() {
fmt.Println("hello world")
variableZeroValue()
variableInitialValue()
variableTypeDeduction()
variableShorter()
}
【注】关于fmt.Println()
package main
import "fmt"
func main() {
a, b, c, d, e := 1, 2, 3, 4, 5
fmt.Println(
a,
b,
c,
d,
e,
)//可以通过逗号来输出多个值,若Println的右括号跟e在同一行,则e后不用加逗号
}
2.2 内建变量类型
2.2.1 变量类型
bool
、string
(u)int
、(u)int8
、(u)int16
、(u)int32
、(u)int64
、uintptr
(指针)byte
、rune
(字符型,32位,不同于其他语言的char
只有1位)float32
、float64
、complex64
、complex128
(complex是复数)
2.2.2 强制类型转换
Go语言中类型转换是强制的
举例:利用math.Sqrt()
计算平方根
var a,b int = 3,4
- 错误写法:
var c int = math.Sqrt(a*a + b*b)
,因为math.Sqrt()
需要传入float64
类型的数据 - 正确写法:
var c int = int( math.Sqrt( float64(a*a + b*b) ) )
,其他语言float
会隐式(即自动转换)的转换成int
,但Go语言不会,需要手动转换
package main
import (
"fmt"
"math"
)
func main() {
var a, b int = 3, 4
var c int = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)//5
}
2.3 常量与枚举
2.3.1 常量
Go语言中的常量不像其他语言在定义的时候要大写
-
常量的关键词是
const
,可以在变量后声明变量的类型,也可以不声明,如:const filename = "abc.txt"
、const a,b = 3,4
、const filename string = "abc.txt"
、const a,b int = 3,4
-
当不对常量进行类型的声明时,如
const a,b = 3,4
,此时的a、b既可以为int
型也可以为float
型,即const
数值可以作为各种类型使用,于是再调用math.Sqrt()
计算以a、b为直角边的三角形的斜边长度时,就无需强制转换了,如下:
package main
import (
"fmt"
"math"
)
func main() {
const a, b = 3, 4
var c int = int(math.Sqrt(a*a + b*b))
fmt.Println(c)//5
}
- 常量也可以在函数外定义作为包内都可以使用的常量
- 常量可以用括号的形式一次性定义多个常量,如下:
package main
import (
"fmt"
"math"
)
const (
a, b = 3, 4
filename = "abc.txt"
)
func main() {
var c int = int(math.Sqrt(a*a + b*b))
fmt.Println(c)//5
fmt.Println(filename)//abc.txt
}
2.3.2 使用常量定义枚举类型
Go语言没有特殊的枚举关键字,一般是用一组const
来定义枚举类型
- 普通枚举类型
- 自增值枚举类型,
iota
关键字代表从0自增1
package main
import "fmt"
func enums1() {
const (
a = 0
b = 1
c = 2
d = 3
e = 4
)
fmt.Println(a, b, c, d, e)
}
func enums2() {
const (
cpp = iota
java
python
golang
)
fmt.Println(cpp, java, python, golang)
}
func enums3() {
const (
aa = iota
_
cc
dd
ee
)
fmt.Println(aa, ee, cc, dd)
}
func enums4() {
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
pb
)
fmt.Println(b, kb, mb, gb, tb, pb)
}
func main() {
enums1() //0 1 2 3 4
enums2() //0 1 2 3
enums3() //0 4 2 3
enums4() //1 1024 1048576 1073741824 1099511627776 1125899906842624
}
2.4 条件语句
2.4.1 if
本节新内容:
- Go语言条件语句格式:
func branch(v int) int {
if v > 100 {
return 100
} else if v < 0 {
return 0
} else {
return v
}
}
nil
关键字相当于别的语言的null
func ReadFile(filename string) ([]byte, error)
方法,用于读取文件,返回值有两个,分别是[]byte
类型和error
类型
以下为读取文件的条件语句流程:若没有abc.txt文件则会报错,需建好此文件才能正确读出
package main
import (
"fmt"
"io/ioutil"
)
func main() {
const filename = "abc.txt"
contents, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
}
- Go语言中的if条件里可以赋值
- if的条件里赋值的变量作用域就只在这个if语句里
以上的代码可以写成以下的形式:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
const filename = "abc.txt"
//在if里面赋值:
if contents, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
//此时再用fmt.println(contents)是不行的,因为它只存在于if区域中
}
2.4.2 switch
Go语言与其他语言中的switch
用法上的区别:
- Go语言中
switch
的每个case
后不像其他语言不用带上break
,Go语言里的switch
会自动break
,除非使用fallthrough
switch
后可以没有表达式panic()
相当于报错,即把程序停下来报出一个错误
例1:
func calculator(a, b int, op string) int {
var result int
switch op {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
panic("unsupported operator:" + op)
}
return result
}
例2:
package main
import "fmt"
func grade(s int) string {
var temp string
switch {
case s < 0 || s > 100:
panic(fmt.Sprintf("wrong score:%d", s))
case s < 60:
temp = "F"
case s <= 70:
temp = "C"
case s <= 80:
temp = "B"
case s <= 100:
temp = "A"
}
return temp
}
func main() {
fmt.Println(
grade(10),
grade(100),
grade(0),
grade(70),
)
}
2.3 循环语句
- Go的循环语句中
if
后不用带括号 - Go中没有
while
关键字
- Go中
for
的初始条件可以省略
例1:二进制数转换器
package main
import (
"fmt"
"strconv"
)
func convertToBin(n int) string {
//二进制思想:设置一个循环,十进制数n用来跟2来取模,其每一次的结果从左往右依次进栈在result里,再进行n/2操作
//如11转换成二进制的过程:
//第一步:11%2 = 1,result = 1,11/2 = 5
//第二步:5%2 = 1,result = 11,5/2 = 2
//第三步:2%2 = 0,result = 011,2/2 = 1
//第四步:1%2 = 1,result = 1011,1/2 = 0
//所以结果是1011
result := ""
if n != 0 {
for ; n > 0; n /= 2 {
result = strconv.Itoa(n%2) + result
}
} else {
result = strconv.Itoa(0)
}
return result
}
func main() {
fmt.Println(convertToBin(0)) //0
fmt.Println(convertToBin(11))//1011
}
2.Go中for
的递增条件可以省略
若for
没有初始条件也没有递增条件,连分号" ; "都能省略
例2:读取文件
package main
import (
"bufio"
"fmt"
"os"
)
func printFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main() {
printFile("abc.txt")
}
- Go中for后可以没有任何内容,此时是死循环
package main
import "fmt"
func forever() {
for {
fmt.Println("abc")
}
}
func main() {
forever()//不停地输出“abc”
}
2.4 函数
-
Go语言中的函数可以返回多个值,并且可以给返回的值起名字
例1:
package main
import "fmt"
//带余数的除法,可以给返回的值起名字
func div(a, b int) (q, r int) {
return a / b, a % b
}
//也可以写成这种形式,但仅用于非常简单的函数
func div2(a, b int) (q, r int) {
q = a / b
r = a % b
return
}
func main() {
fmt.Println(div(11, 2))//5 1
}
例2:
package main
import "fmt"
func calculator(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 "/":
q, _ := div(a, b) //当返回值有多个,但只想接收一个返回值时,可以用下划线“_”来省略接收的变量
return q, nil
default:
return 0, fmt.Errorf("unsupported operation:%s", op)
}
}
//带余数的除法
func div(a, b int) (q, r int) {
return a / b, a % b
}
func main() {
if result, err := calculator(11, 2, "+"); err != nil {
fmt.Println("error:", err)
} else {
fmt.Println(result)
}
}
- 函数式编程
- Go语言的函数可以传递函数进去,即函数的参数也可以是一个函数
- 在调用一个参数有函数的函数时,可以直接在调用时现场编写一个函数,此函数无需给名字,即匿名函数
- 例2的
switch
计算器太low,以下的例子通过传递math
中的函数来进行数值运算
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
//op是传递进去的函数名字,op是一个传入两个int返回一个int的函数,apply是一个传入一个函数和两个int返回一个int的函数
//apply()函数return的是op(a,b)的结果
func apply(op func(int, int) int, a, b int) int {
p := reflect.ValueOf(op).Pointer()
opName := runtime.FuncForPC(p).Name() //拿到传入函数的名字
fmt.Printf("Calling function %s with args "+
"(%d,%d)\n", opName, a, b) //打印调用的函数名字以及进行运算的两个参数
return op(a, b)
}
//因为pow()传入的两个参数是float64型,所以对其进行重写,使其传入的两个参数是int型
func pow(a, b int) int {
return int(math.Pow(float64(a), float64(b)))
}
func main() {
fmt.Println(apply(pow, 3, 4))
//在调用一个参数有函数的函数时,可以直接在调用时现场编写一个函数,此函数无需给名字,即匿名函数,如下:
fmt.Println(apply(
func(a, b int) int {
return int(math.Pow(float64(a), float64(b)))
}, 3, 4))
}
- 可变参数列表
Go语言没有默认参数、可选参数、函数重载,只有可变参数列表
package main
import "fmt"
func sum(numbers ...int) int {
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
func main() {
fmt.Println(sum(1, 2, 3)) //6
fmt.Println(sum(1, 2, 3, 4)) //10
fmt.Println(sum(1, 2, 3, 5)) //11
}
2.5 指针
2.5.1 Go语言的指针特点
- Go语言的指针不能运算
- Go语言的指针具体格式如下:
package main
import "fmt"
func main() {
var a int = 2
var pa *int = &a
*pa = 3
fmt.Println(a)
}
2.5.2 Go语言的参数传递
Go语言只有值传递一种方式,但Go可以通过指针来实现引用传递的作用
Go语言指针实例:
package main
import "fmt"
func main() {
var a = 2
var b = &a
var c *int = &a
*c = 3
fmt.Println(a, *b) //3 3
}
go语言的参数传递只能是值传递,所以这里实际上相当于在函数中拷贝了一个a进行操作
同理这里是拷贝了a的地址,pa指向a的值,可以通过修改pa指向的值来达到修改数值的目的
函数内是拷贝了一份cache结构中指向data的指针
pData
来达到改变data的目的
下面列举数个交换两变量数值的方法:
package main
import "fmt"
//这样互换值的方法是正确的
func swap1(a, b *int) {
*a, *b = *b, *a
}
//失败的互换方法
func swap2(a, b *int) {
*a = *b
*b = *a
}
//引用第三个值来将两个值互换
func swap3(a, b *int) {
c := *a
*a = *b
*b = c
}
//最好的互换数值的方式
func swap4(a, b int) (int, int) {
return b, a
}
func main() {
a, b := 3, 4
a, b = swap4(a, b)
fmt.Println(a, b) //4 3
}
标签:Println,main,int,fmt,语法,var,func,Go,第二章 来源: https://www.cnblogs.com/Ayisprite/p/16435370.html