函数
1.函数可以没有参数或接受多个参数。
2.当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它都可以省略。
在本例中,add 接受两个 int 类型的参数。
注意类型在变量名 之后。
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
//或者
func add2(x,y int) int{
return x+y
}
func main() {
fmt.Println(add(3, 4))
fmt.Println(add2(3, 4))
}
7
7
多值返回
swap
//多值返回
func swap (x,y string ) (string,string){
return y,x
}
func main() {
fmt.Println(swap("hello","world"))
}
world hello
Go 的返回值可被命名,它们会被视作定义在函数顶部的变量。
返回值的名称应当具有一定的意义,它可以作为文档使用。
没有参数的 return 语句返回已命名的返回值。也就是 直接 返回。
直接返回语句应当仅用在下面这样的短函数中。在长的函数中它们会影响代码的可读性。
func add2(x,y int) (sum,diff int){
return x+y , x-y
}//仅用在下面这样的短函数中。在长的函数中它们会影响代码的可读性
func add2(x,y int) (sum,diff int){
sum =x+y
diff =x-y
return
}
func main() {
fmt.Println(add2(3,4))
}
变量
var 语句用于声明一个变量列表,跟函数的参数列表一样,类型在最后。
就像在这个例子中看到的一样,var 语句可以出现在包或函数级别。
var a,b,c,d bool
func main() {
var a = true
fmt.Println(a,b,c,d)
}
true false false false
变量的初始化
变量声明可以包含初始值,每个变量对应一个。
如果初始化值已存在,则可以省略类型;变量会从初始值中获得类型。
var a,b,c,d int = 1,2,3,4
func main() {
var e = true //初始化值已存在,省略类型,变量从初始值中获得类型,true是bool型,直接定义e为bool
fmt.Println(a,b,c,d,e)
}
1 2 3 4 true
短变量声明
在函数中,简洁赋值语句 := 可在类型明确的地方代替 var 声明。
函数外的每个语句都必须以关键字开始(var, func 等等),因此 := 结构不能在函数外使用。
func add2(x,y int) (sum,diff int){
z:=3 //:= 结构不能在函数外使用
sum=x+y
diff=x-y+z
return
}
Go 的基本类型有
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名
// 表示一个 Unicode 码点
float32 float64
complex64 complex128
本例展示了几种类型的变量。 同导入语句一样,变量声明也可以“分组”成一个语法块。
int, uint 和 uintptr 在 32 位系统上通常为 32 位宽,在 64 位系统上则为 64 位宽。 当你需要一个整数值时应使用 int 类型,除非你有特殊的理由使用固定大小或无符号的整数类型。
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
s float32 = 2.1
n float64 =3.3
t byte =33
m rune =32
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
零值
没有明确初始值的变量声明会被赋予它们的 零值。
零值是:
数值类型为 0,
布尔类型为 false,
字符串为 ""(空字符串)。
0 0 false ""
类型显式转换
Go 在不同类型的项之间赋值时需要显式转换。 例子中 float64 或 uint 和之前的类型不一致 必须声明类型
package main
import (
"fmt"
"math"
)
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
}
类型推导
在声明一个变量而不指定其类型时(即使用不带类型的 := 语法或 var = 表达式语法),变量的类型由右值推导得出。
当右值声明了类型时,新变量的类型与其相同:
var i int
j := i // j 也是一个 int
不过当右边包含未指明类型的数值常量时,新变量的类型就可能是 int, float64 或 complex128 了,这取决于常量的精度:
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
尝试修改示例代码中 v 的初始值,并观察它是如何影响类型的。
package main
import "fmt"
func main() {
v := "jjj"// 修改这里!
fmt.Printf("v is of type %T\n", v)
}
常量
常量的声明与变量类似,只不过是使用 const 关键字。
常量可以是字符、字符串、布尔值或数值。
常量不能用 := 语法声明。
package main
import "fmt"
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
循环
go只有一种循环 for
组成:
for 初始化;条件表达式;后置语句{
循环体
}
一旦条件表达式的布尔值为 false,循环迭代就会终止。
注意:和 C、Java、JavaScript 之类的语言不同,Go 的 for 语句后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
初始化语句和后置语句是可省略。
go中的while
package main
import "fmt"
func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
无限循环
如果省略循环条件,该循环就不会结束,因此无限循环可以写得很紧凑
func main() {
for {
}
}
没有条件的 switch
没有条件的 switch 同 switch true 一样。
这种形式能将一长串 if-then-else 写得更加清晰。
switch {
case today>"2019-01-01 00:00:00":
fmt.Print("ssss")
case today<"2020-02-02":
fmt.Print("dssds")
default:
fmt.Print("default")
}
defer
defer 语句会将函数推迟到外层函数返回之后执行。
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。
defer fmt.Println("word")
fmt.Println("hello")
print、printf、printIn区别:
https://blog.csdn.net/geniushorse/article/details/53490148
defer 栈
推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
func defers(){
fmt.Println("begin")
for i:=0;i<10;i++{
defer fmt.Println(i)
}
fmt.Println("end")
}
begin
end
9
8
7
6
5
4
3
2
1
0
指针
Go 拥有指针。指针保存了值的内存地址。
类型 * T是指向T类型的指针 。其零值为 nil。
var p *int
&操作符会生成
有点难,一会再补
slice和array
概念:
数组:类型[n]T 表示拥有n个T类型的值的数组
切片:类型[]T 表示一个元素为T类型的切片
表达式:
数组:var a [10]int
声明变量a为10个整数的数组
切片:a[low:high]
low:下界 high:上界 区间为半闭半开
以下表达式创建了一个切片,它包含 a 中下标从 1 到 3 的元素:a[1:4]
长度:
数组:长度是类型的一部分,不可变
切片:为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用
切片的长度就是它所包含的元素个数。
切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。
举例:
数组:
name := [4]string{
"a","b","c","d",
}
[3]bool{true, true, false}
切片(初始化):
name := []string{
"a","b","c","d",
}
[]bool{true, true, false}
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
用 make 创建切片
make 函数会分配一个元素为零值的数组并返回一个引用了它的切片:
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
a := make([]int, 5) // len(a)=5
要指定它的容量,需向 make 传入第三个参数:
make([]T, length, capacity) //这里 len 是数组的长度并且也是切片的初始长度
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
这里 len 是数组的长度并且也是切片的初始长度
append
func append(s []T, vs ...T) []T
append 的第一个参数 s 是一个元素类型为 T 的切片,其余类型为 T 的值将会追加到该切片的末尾。
append 的结果是一个包含原切片所有元素加上新添加元素的切片。
当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。返回的切片会指向这个新分配的数组。
var numbers[]int
numbers=append(numbers,2,3,4)
//这里需要赋值给追加数组的名字,不然会报错
copy
var numbers[]int
copy (numbers1,numbers)
nil
func main() {
var numbers []int
fmt.Printf("len=%d cap=%d slice=%v\n",len(numbers ),cap(numbers ),numbers )
if(numbers == nil){
fmt.Printf("切片是空的")
}
}
range
for 循环的 range 形式可遍历切片或映射。
可以将下标或值赋予 _ 来忽略它。
for i, _ := range pow
for _, value := range pow
若你只需要索引,忽略第二个变量即可。
for i := range pow