目录
1.变量的定义
1.1当使用var关键字的时候
var a,b,c bool
var s1,s2 string ="hello world"
可以放在函数内,或者直接放在包内
可以使用var()集中定义变量
1.2可以让编译器自动决定类型
var a,b,i,s1,s2=true,false,3,“hello”,“world”
1.3使用:=定义变量
a,b,i,s1,s2:=true,false,3,"hello","world"
只能在函数内使用
2.内建变量类型
bool,string
(u)int,(u)int8,(u)int16,(u)int32,(int)64,uintptr(加上“u”就是无符号整数,不加就是有符号整数,后面的数字是规定长度,不规定长度是根据系统来,系统多少位就占多少位,最后一个是指针)
byte,rune(byte是8位的,rune是go语言的字符类型,32位,相当于别的语言的“char”)
float32,float64,complex64,complex128(complex是指复数,complex64的实虚部是32位的float,complex128的实虚部是64位的float)
2.1complex类型
c := 3 + 4i
fmt.Println(cmplx.Abs(c))
结果是5
2.2强制类型转换
go语言只有强制类型转换
例如:求直角边为3,4的三角形的斜边长,只能这样写:
var a, b int = 3, 4
var c int
c = int(math.Sqrt(float64(a*a + b*b)))
fmt.Println(c)
3.常量与枚举
3.1常量
func consts() {
const filename = "abc.txt"
const a, b = 3, 4
var c int
c = int(math.Sqrt(a*a + b*b))
fmt.Println(filename, c)
}
常量是指定义后不能修改的量,定义常量的时候可以和自变量定义一样在后面加上类型,也可以不加。
但是当不加类型的时候,就比较有意思了,它的类型是不确定的,当你在用它的时候需要它是什么类型它就是什么类型,如上面的代码中math.Sqrt()需要传入float类型,此时它就是float类型的。
也可以使用括号来定义
func consts() {
const (
filename = "abc.txt"
a, b = 3, 4
)
var c int
c = int(math.Sqrt(a*a + b*b))
fmt.Println(filename, c)
}
3.2枚举
func enums() {
const (
cpp = 0
java = 1
python = 2
golang = 3
)
fmt.Println(cpp, java, python, golang)
}
go语言里面用常量定义枚举类型,如上,结果为0123
但是go里面提供了一种自增值实现,如下,结果依然为0123
func enums() {
const (
cpp = iota
java
python
golang
)
fmt.Println(cpp, java, python, golang)
}
还可以作为种子来定义枚举类型,如下。
func enums() {
const (
cpp = iota
_
python
golang
javascrip
)
//b,kb,mb,gb,tb,pb
const (
b = 1 << (10 * iota)//左移0位
kb//左移10位
mb//左移20位
gb//左移30位
tb//左移40位
pb//左移50位
)
fmt.Println(cpp, javascrip, python, golang)
fmt.Println(b, kb, mb, gb, tb, pb)
}
//结果为:
//0 4 2 3
//1 1024 1048576 1073741824 1099511627776 1125899906842624
到这里为止,以上第一部分内容所有demo的整个代码如下:
package main
import (
"fmt"
"math"
"math/cmplx"
)
var (
aa = 3
ss = "kkk"
bb = true
)
func variableZeroValue() {
var a int
var s string
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 variableTypeDeduction() {
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"
b = 5
fmt.Println(a, b, c, s)
}
func euler() {
fmt.Printf("%.3f\n", cmplx.Exp(1i*math.Pi)+1)
}
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 = "abc.txt"
a, b = 3, 4
)
var c int
c = int(math.Sqrt(a*a + b*b))
fmt.Println(filename, c)
}
func enums() {
const (
cpp = iota
_
python
golang
javascrip
)
//b,kb,mb,gb,tb,pb
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
pb
)
fmt.Println(cpp, javascrip, python, golang)
fmt.Println(b, kb, mb, gb, tb, pb)
}
func main() {
fmt.Println("hello world") //打印语句
variableZeroValue() //不赋值的变量声明方式
variableInitialValue() //赋值的变量声明方式
variableTypeDeduction() //不带类型的变量声明方式
variableShorter() //用冒号定义变量,但只能在函数内使用
fmt.Println(aa, ss, bb) //打印包内变量
euler() //实现欧拉公式
triangle() //强制类型转换举例
consts() //常量举例
enums() //枚举类型举例
}
4.条件语句
4.1if
写一个读文件的demo,如下。
func main() {
const filename = "abc.txt"
centents, err := ioutil.ReadFile(filename)//第一个参数是文件内容,第二个参数是报错信息
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", centents)
}
}
go语言可以把if写成这样:
func main() {
const filename = "abc.txt"
if contents, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
}
但是这种写法,centents是不能在if模块外面用了,也就是作用域仅在if里面。
4.2switch
写一个demo如下。
func grade(score int) string {
g := ""
switch {
case score < 0 || score > 100:
panic(fmt.Sprintf("Wrong score:%d", score))
case score < 60:
g = "F"
case score < 80:
g = "C"
case score < 90:
g = "B"
case score < 100:
g = "A"
}
return g
}
注意:switch后面可以跟一个符号,例如score。但是也可以不跟。每个case最后不用写break,默认每个case后面都有一个break,如果希望没有break,那就加上一个fallthrough。
5.循环
func forDemo() {
sum := 0
for i := 0; i < +100; i++ {
sum += i
}
fmt.Println(sum)
}
//结果是4950
for的条件里不需要括号的。
for的条件里可以省略初始条件,结束条件,递增表达式。
下面是一个十进制转二进制的demo:
func convertToBin(n int) string {
result := ""
for ; n > 0; n /= 2 {
lsb := n % 2
result = strconv.Itoa(lsb) + result //lsb要转成字符串
}
return result
}
//这里的初始条件是省略的
下面是逐行读取文件内容的demo:
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())
}
}
//这里省略了初始条件和递增条件
下面是省略初始条件,结束条件,递增条件的demo:
func forver() {
for {
fmt.Println("毛同学")
}
}
//这里省略了起始条件,终止条件,递增条件。
go语言里面没有while
到这里为止,以上第二部分内容所有demo的整个代码如下:
package main
import (
"fmt"
"io/ioutil"
)
func grade(score int) string {
g := ""
switch {
case score < 0 || score > 100:
panic(fmt.Sprintf("Wrong score:%d", score))
case score < 60:
g = "F"
case score < 80:
g = "C"
case score < 90:
g = "B"
case score < 100:
g = "A"
}
return g
}
func main() {
const filename = "abc.txt"
if contents, err := ioutil.ReadFile(filename); err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n", contents)
}
fmt.Println(
grade(0),
grade(59),
grade(60),
grade(82),
grade(99),
grade(100),
grade(101),
)
}
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func forDemo() {
sum := 0
for i := 0; i < +100; i++ {
sum += i
}
fmt.Println(sum)
}
func convertToBin(n int) string {
result := ""
for ; n > 0; n /= 2 {
lsb := n % 2
result = strconv.Itoa(lsb) + result //lsb要转成字符串
}
return result
}
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 forver() {
for {
fmt.Println("毛同学")
}
}
func main() {
forDemo()
fmt.Println(
convertToBin(5), //101
convertToBin(13), //1101
convertToBin(72387885),
)
printFile("abc.txt")
forver()
}
6.函数
一般定义的形式为:
func eval(a,b int op string) int
以下是返回一个值的简易计算器demo:
func eval(a, b int, op string) int {
switch op {
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
return a / b
default:
panic("unsupported operation:" + op)
}
}
以下是两个返回值的函数,为带余数的除法的实现demo:
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
}
x, y := div(10, 3)//用x和y来接收这两个返回值
fmt.Println(x, y)
//与上面的值一样的结果
当函数有两个返回值,但是只想用其中一个返回值的时候:
func div(a, b int) (q, r int) {
q = a / b
r = a % b
return
}
x, _ := div(10, 3)//用x和y来接收这两个返回值
fmt.Println(x)
//与上面的值一样的结果
用“_”就可以了
go语言是一种函数式编程语言,用函数式编程修改建议计算器代码,如下:
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)
}
//这里参数有3个,第一个是函数op,然后是a,b
fmt.Println(apply(func(a int, b int) int {
return int(math.Pow(float64(a), float64(b)))
}, 3, 4))
//这里首先传入了一个匿名函数,然后传入了3和4
go语言没有c++的那种什么重载啊之类的复杂的语法,但是有可变参数列表:
func sum(numbers ...int) int {
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
//这里的...int的意思就是无论你传入多少个参数都可以
fmt.Println(sum(1, 2, 3, 4, 5))
到这里为止,以上第三部分内容所有demo的整个代码如下:
package main
import (
"fmt"
"math"
"reflect"
"runtime"
)
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:
return 0, fmt.Errorf("unsupported operation:%s", op)
}
}
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)
}
func div(a, b int) (q, r int) {
q = a / b
r = a % b
return
}
func sum(numbers ...int) int {
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
func main() {
fmt.Println(eval(3, 4, "*"))
x, y := div(10, 3)
fmt.Println(x, y)
if result, err := eval(3, 4, "x"); err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(result)
}
fmt.Println(apply(func(a int, b int) int {
return int(math.Pow(float64(a), float64(b)))
}, 3, 4))
fmt.Println(sum(1, 2, 3, 4, 5))
}
7.指针
和c语言不同,go语言的指针相对简单,简单在go语言的指针不能运算。
var a int =2 //定义了变量a,赋值为2
var pa *int=&a //定义了一个指针,指向了a
*pa=3
fmt.Println(a)
//这里打印结果为3
那么,go语言的函数是值传递还是引用传递?
在c++中如下代码:
void pass_by_val(int a){
a++;
}
void pass_by_ref(int& a){
a++;
}
int main(){
int a =3;
pass_by_val(a);
printf("After pass_by_val:%d\n",a);
pass_by_ref(a);
printf("After pass_by_ref:%d\n",a);
}
//结果应该是3,4
值传递是把传入的值拷贝了一份给函数,本身是不受函数内影响的,类似于“借你用”。
引用传递是指把地址“告诉”了函数,这个函数是与变量共享的,类似于“一起用”。
上面这个demo是c++,它可以值传递也可以引用传递,java,python大多都是引用传递。
Go语言只有值传递一种方式。
那么当交换两个参数值,可以这样实现:
func swap(a, b int) (int, int) {
return b, a
}
a, b := 3, 4
a, b = swap(a, b)
fmt.Println(a, b)
于2021年11月9日整理