go 基础语法 (程序结构控制)
条件语句
- if
- if的条件里是不需要括号的
- if 的条件里可以赋值
- if 条件里赋值的变量作用于就在这个 if 语句里面
func readsfile() {const filename = "abc.txt" // 注意创建文件// 写法1 比较多// go 语言的函数是可以返回两个值的
countents, err := ioutil.ReadFile(filename)if err != nil {
fmt.Print(err)} else {
fmt.Printf("%s\n", countents)}// 写法2 if可以跟多个语句if countents, err := ioutil.ReadFile(filename); err != nil {
fmt.Print(err)} else {
fmt.Printf("%s\n", countents)}
}
- switch
- switch 会自动 break, 除非使用 fallthrough
- switch 后可以没有表达式
- panic 会自动报错
func grade(score int) string {
g := ""switch {case score < 0 || score > 100:panic(fmt.Sprintf("Wrong scor: %d", score))case score < 60:
g = "F"case score < 80:
g = "C"case score < 90:
g = "B"case score <= 100:
g = "A"// default:// panic(fmt.Sprintf("Wrong scor: %d", score))}return g
}
// 函数入口
func main() {
fmt.Println(grade(0),grade(20),grade(50),grade(69),grade(98),grade(100),// grade(101), // grade 报错不会返回前面的已经运算的结果,是直接跳出err)
}
循环
- for
- for 的条件里不需要括号
- for 的条件里面可以省略初始条件,结束条件,递增表达式
- 省略初始条件相当于while, go 语言中没有 while
- 省略所有条件就是死循环
func converToBin(n int) string {// 省略初始条件
result := ""for ; n > 0; n /= 2 {
lsb := n % 2
result = strconv.Itoa(lsb) + result
}return result
}
func printFile(filename string) {
file, err := os.Open(filename)if err != nil {panic(err)}
scanner := bufio.NewScanner(file)// 省略递增条件,省略初始条件,只有结束条件// 相当于while, go 语言中没有whilefor scanner.Scan() {
fmt.Println(scanner.Text())}
}
func forever(){// 省略所有条件就是死循环// 死循环设计的这么好写是因为 go 中死循环使用的频率很高for {
fmt.Println("hello")}
}
// 函数入口
func main() {
fmt.Println(converToBin(5),converToBin(13),converToBin(23333),converToBin(0),)printFile("abc.txt")forever()
}
函数
- 函数格式
func eval(a, b int, op string) int
函数名在前 类型在后 - 函数可以返回多个值
- 函数返回多个值可以起名(起名适用于非常简单的函数),对于调用者而言没有区别
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, nil
default:// 函数的多返回值不要乱用,一般是一个返回值,加一个 err// panic("unsupported operation:" + op) // panic 直接报错中断程序,不建议使用return 0, fmt.Errorf("unsupported operation: %s", op)}}
// 取余
func div(a, b int) (q, r int) {// q,r 方便他人理解,返回值可以取个名字return a / b, a % b
// 但是如果函数体过长,使用这这方法来 return 看起来会很累// q = a / b// r = a % b// return}
// 函数入口
func main() {
fmt.Println(eval(3, 4, "*"))if result, err := eval(2, 3, "x"); err != nil {
fmt.Printf("Error:", err)} else {
fmt.Println(result)}// fmt.Println(div(13, 4))
q, r := div(13, 4)
s, _ := div(13, 4) // go 语言定义的变量一定要使用到,两个返回的变量就可以使用 _ 跳过不需要的返回值
fmt.Println(q, r, s)}
- 函数式编程:函数的条件,参数包括函数内都可以嵌套函数
// 简化上面的方法,不需要那么复杂的switch
func apply(op func(int, int) int, a, b int) int {return op(a, b)}
// 定义一个函数不需要再去转换浮点
func pow(a, b int) int {return int(math.Pow(float64(a), float64(b)))}
// 函数入口
func main() {
fmt.Println(apply(pow, 2, 4))// 如果觉得定义一个包比较麻烦,也可以直接写一个匿名函
fmt.Println(apply(func(a, b int) int {return int(math.Pow(float64(a), float64(b)))}, 2, 4))}
- go 语言函数没有默认参数,可选参数,参数重载.
- 只有一个可变参数列表
// ...int 代表随意传多少个int都可以
func sum(numbers ...int) int {
s := 0for i := range numbers {
s += numbers[i]}return s
}
// 函数入口
func main() {
fmt.Println(sum(1, 2, 3, 4, 5)) // 15}
指针
- go 的指针不能运算
- go 只有值传递一种方式
- (值传递:拷贝,原函数中的值不会变. 引用传递:会改变原函数中的值)
- (值传递)
- (通过指针+值传递实现引用传递的效果)
(object 的传递)
- 例子
func swap(a, b *int) {*a, *b = *b, *a
}
// 函数入口
func main() {
a, b := 3, 4swap(&a, &b)
fmt.Println(a, b)}