一. 变量定义
package main
import "fmt"
var (
// 函数外的变量 并非全局变量, 而是包内变量
aa = 3
ss = "kkk"
)
// 函数外面 不能用:=定义变量
func variableZeroValue() {
var a int
var s string // go语言的变量 在定义的时候就会有一个 初始值
fmt.Printf("%d %q\n", a, s)
}
func variableInitialValue() {
var a, b int = 3, 4
var s string = "abc"
fmt.Println(a, b, s)
}
func varibleTypeDeduction() {
var a, b, c, s = 3, 4, true, "def"
fmt.Println(a, b, c, s)
}
func variableShorter() {
a, b, c, s := 3, 4, true, "def" // := 和 var = 一个意思, 只能在第一次定义变量时用
b = 5
fmt.Println(a, b, c, s)
}
func main() {
fmt.Println("Hello world")
variableZeroValue()
variableInitialValue()
varibleTypeDeduction()
variableShorter()
fmt.Println(aa, ss)
}
二. 内建变量类型
- bool, string
- (u)int, (u)int8, (u)int16, (u)int32, (u)int64, 带u表示无符号整型
- uintptr ptr表示指针
- byte
- rune 字符型 32位 go中不叫char,优化了char, 避免了很多坑
- float32, float64
- complex64, complex128 复数
复数演示
func euler() {
c := 3 + 4i //定义复数
fmt.Println(cmplx.Abs(c)) // 得到5
fmt.Println(
cmplx.Exp(1i*math.Pi), // 或者
cmplx.Pow(math.E, 1i*math.Pi)) // i不会解释为复数, 需要写成1i
//(-1+1.2246467991473515e-16i) (-1+1.2246467991473515e-16i)
// 去掉尾巴 可以使用 fmt.Printf("%0.3d", cmplx.Exp(1i*math.Pi))
}
go只有强制类型转化
func trangle() {
var a, b int = 3, 4
var c int
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)
// 如果写 var c int = math.Sqrt(a*a, b*b) 会失败, go只能强制类型转化, 无法自动转
}
三. 常量和枚举
常量
- 例如 const filename = "abc.txt"
- const 类型可以作为各种类型使用
func consts() {
const filename = "abc.txt"
const a, b = 3, 4
var c int
c = int(math.Sqrt(a*a + b*b)) //const 类型可以作为各种类型使用,这里会作为float
fmt.Println(filename, c)
}
枚举
- 普通枚举类型
- 自增值枚举类型
func enums() {
//const(
// cpp = 0
// java = 1
// python = 2
// golang = 3
//)
// 可以简化为
const (
cpp = iota
_ // _表示跳过 1
python //2
golang //3
javascript //4
)
fmt.Println(cpp, javascript, python, golang) // 0, 4, 2,3
// iota更复杂的用法, 可以作为自增值的 种子
const (
b = 1 << (10*iota)
kb
mb
gb
tb
pb
)
fmt.Println(b, kb, mb, gb, tb, pb) //1 1024 1048576 1073741824 1099511627776 1125899906842624
}
四. 条件语句
if
import (
"io/ioutil"
"fmt"
)
func ifexample() {
const filename = "abc.txt"
// 常规用法
//contents, err = ioutil.ReadFile(filename)
//
//if err != nil {
// fmt.Println(err)
//} else {
// fmt.Printf("%s\n", contents)
//}
// if后面可以跟 多个语句的
// if语句中可以定义变量
if contents, err := ioutil.ReadFile(filename); err == nil {
fmt.Println(string(contents))
} else {
fmt.Println("cannot print file contents:", err)
}
// if后的变量只在 if范围内起作用
}
switch
- switch 会自动break, 如果不想break, 加fallthrough
func grade(score int) string {
g := ""
switch {
case score < 60 && score >= 0:
g = "F"
case score < 80:
g = "C"
case score < 90:
g = "B"
case score <= 100:
g = "A"
default:
panic(fmt.Sprintf("Wrong score: %d", score)) // panic会终断程序的执行, 并报错
}
return g
}
func main() {
fmt.Println(
grade(0),
grade(55),
)
}
五. 循环
- for 的条件里不加括号
- for的条件里可以省略初始条件, 结束条件, 递增表达式
sum := 0
for i:= 1; i <= 100; i++ {
sum += 1
}
实际举例
package main
import (
"fmt"
"strconv"
"os"
"bufio"
)
func convertToBin(n int) string { // 10进制转2进制
result := ""
for ; n > 0; n /= 2 {
lsb := n%2
result = strconv.Itoa(lsb) + result
}
if result=="" {
result = "0"
}
return result
}
func printFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() { // 这里的for 没有起始条件和递增条件 只有结束条件 就相当于while go语言中没有while
fmt.Println(scanner.Text())
}
}
func forever() {
for { // 没有起始条件, 没有递增条件, 也没有结束条件 相当于死循环
fmt.Println("abc")
}
}
func main() {
fmt.Println(
convertToBin(5), // 101
convertToBin(13), // 1101
convertToBin(0), // 0
)
printFile("abc.txt")
}
六. 函数
- 函数名在前 , 返回值类型在后, 参数也是如此
- 可以将函数作为参数
- 可以返回多个值
- go没有 默认参数, 可选参数, 重载等复杂操作, 只有可变参数列表...
- go的匿名函数 就是 直接省略函数名
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
func eval(a, b int, op string) (int, error) {// error返回错误
switch op {
case "+":
return a + b, nil // 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 apply(op func(int, int) int, a, b int) int { // 传入参数op 是函数
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)
}
func sum(numbers ...int) int { // ...参数列表, 可以传任意数量的int
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
func swap(a, b int) (int, int) {
return b, a
}
func main() {
fmt.Println("Error handling")
if result, err := eval(3, 4, "x"); err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(result)
}
q, r := div(13, 3) // 接收返回值
fmt.Printf("13 div 3 is %d mod %d\n", q, r)
fmt.Println("pow(3, 4) is:", apply(
func(a int, b int) int { // 使用go语言的 匿名函数
return int(math.Pow(
float64(a), float64(b)))
}, 3, 4))
fmt.Println("1+2+...+5 =", sum(1, 2, 3, 4, 5))
a, b := 3, 4
a, b = swap(a, b)
fmt.Println("a, b after swap is:", a, b)
}
七. 指针
- 指针不能运算
- go的函数参数都是值传递, 想要达到引用传递的效果, 可以使用指针
func swap(a, b *int){
*a, *b = *b, *a
}
func main() {
a, b := 3, 4
swap(&a, &b)
}
交换值有更好的方法
func swap(a, b int) (int, int) {
return b, a
}
func main() {
a, b := 3, 4
b, a = swap(a, b)
}