go变量
// 变量可以以字母,数字,下划线组成,但是只能以数字或下划线开头
var varibale type = value
var varuable = value // 根据值类型自动推断类型
var variable_1 type
variable_1 = value
// 1. 已经声明的变量不能使用以下方式赋值。:= 左侧的变量不应该时已经被声明过的。
// 2. 同时不带声明格式的只能在函数体中出现。
// 3. 使用:= 赋值的变量不能再次使用:=赋值。否则 提示编译错误:no new variables on left side of :=
// 4.go中如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误。a declared and not used.
// 5. 全局变量允许声明但不使用。
// 6.如果想要交换两个变量的值,可以简单使用a, b = b, a
// 空白标识符 _ 用于弃值。他实际上是一个只写变量,你不能得到它的值。常用于函数返回时不需要使用。
variable_2 := value
var vn1, vn2, vn3 = value // 多个变量
// 这中方式一般用于声明全局变量
var (
vname1 type
vname2 type
)
变量的作用域:
全局变量和局部变量:局部变量的名称可以和局部变量相同,会根据就近原则使用:
初始值:
int/float 0
pointer nil
go常量
// 常量使用关键字const声明,常量可以不被使用
const vn [type] = value
// 1. iota是一个特殊的值,可以认为是一个可以被编译器修改的常量,iota在关键字出现时被置为0.每当iota在新的一行被使用时,都会自动加1.
// 2.常量为被赋值时,将自动使用上一行已赋值的值
// 3.常量可以使用表达式len,cap unsafe.sizeof等赋值,但是只能使用内置函数。
const(
e = 0
f
g
)
const (
a = iota
b = iota
c = iota
)
go运算符
// 算术运算符:
+ - * / % += --
// 关系运算符:
== != < > >= <=
// 逻辑运算符:
&& || !
// 位运算符:
& | ^ << >>
// 赋值运算符:
= += -= *= %= <<= >>= &= ^= |=
// 其他:
& 返回变量地址
* 指针变量
// 优先级:
! ^
* / % >> << & &^
+ - | ^
== != < <== >= >
<-
&&
||
go条件语句和循环语句(for)
// if条件语句,与其他语言不同,go的if判断语句不需要括号即可
var a = 1
if a == 1 {
fmt.Println("a = ", a)
}
// switch-case语句:
// 1. 可以在switch语句中判断x的类型。只能在switch中使用
// 2. default可选
// 3. fallthrough强制执行下一条语句.判断类型时不能用fallthrough;fallthrough不能用在最后一个case语句;fallthrough从第一个case正确的语句开始生效
// 4. 可选break。默认每个语句自带break
// 5. case语句中不能有多个重复条件:duplicate case
// 6. case语句中可以判断多个条件
// 7. switch不指定内容,case指定true,false时,case条件可以重复
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf(" x 的类型 :%T",i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型" )
default:
fmt.Printf("未知型")
}
// select语句。select随机执行一个可运行的case。如果没有可运行的case,它将阻塞。知道case可运行。
// 每个case都必须是一个通信
// 所有channel表达式都会被求值
// 所有被发送的表达式都会被求值
// 如果任意某个通信可以进行,它将执行,其他被忽略。
// 如果有多个case可运行,select会随机公平的选出一个运行,其他不会执行。
// 如果有default自居,则执行该语句。
// 如果没有default子句。select将阻塞。直到某个通信可以运行。go不会重新对channel或值进行求值。
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
// 循环语句:同基本的循环语句
// 可以使用goto语句,continue, break等
t := 1
for t < 20 {
fmt.Println("t = ", t)
t++
}
// sample goto
var a int = 10
/* 循环 */
LOOP: for a < 20 {
if a == 15 {
/* 跳过迭代 */
a = a + 1
goto LOOP
}
fmt.Printf("a的值为 : %d\n", a)
a++
}
go值类型和引用类型
// 值类型:变量直接存储值,内存通常在栈中分配,栈在函数调用完后会释放
int
float
bool
string
array
struct
// 引用类型:变量存储的是一个地址,这个地址存储最终的值,内存通常在堆上分配。通过GC回收
// 指针
pointer
slice
map
chan
go的内存管理
go函数(go函数默认是值传递)
// 参数类型相同,多个返回值
func maxNew(n1, n2 int) (int, error)
// 参数类型不同
func swap(x string, y int) int
// go函数默认是值传递,如果要使用引用传递,需要使用指针
func swap(x, y *int)
// go的闭包:
func cmpAndPrint() (func(n int), func(n int)){
compare := 20
return func(n int){
if n > compare {
fmt.Println("n is largger than 20")
}
}, func(n int) {
if n < compare {
fmt.Println("n is smaller than 20")
}
}
}
关于go的闭包,网上非常好的例子:
https://www.cnblogs.com/cxying93/p/6103375.html
https://www.cnblogs.com/hzhuxin/p/9199332.html
闭包就是外部函数能够访问函数内部的变量。根本上说是为了函数内外进行沟通。
闭包的用处有两个:
-可以读取函数内部的变量
-另一个是让这些变量的值始终保持在内存中,不会在函数被调用后被自动清除。
闭包注意点:
- 闭包会使得函数中的变量都被保存在内存中,内存消耗很大。所以不能滥用闭包。否则会造成性能问题。
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值
指针变量
var var_name *var-type
var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:
var ip int / 指向整型*/
var fp float32 / 指向浮点型 */
在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。
var a int = 20
var ip int
fmt.Printf("ip 变量的值: %d\n", *ip ) // 20
当一个指针被定义后没有分配到任何变量时,它的值为nil。nil成为空指针。
go for 循环指针异常:
go在for循环中,不论是普通的for循环,还是range循环,每次分配给变量的值总是保存在一个固定的地址上,这就会导致我们使用指针时,得到的指针数组的是相同的。如例:
for ins := 0; ins < len(arr); ins++ {
fmt.Println("=========", &ins)
// newarr = append(newarr, arr[ins])
newarr = append(newarr, ins)
// ptrlist[ins] = &arr[ins]
ptrlist = append(ptrlist, &ins)
}
for _, ptr := range ptrlist {
fmt.Println(ptr)
fmt.Println(*ptr)
}
结果示例:
========= 0xc000056330
========= 0xc000056330
========= 0xc000056330
========= 0xc000056330
========= 0xc000056330
0xc000056330
5
0xc000056330
5
0xc000056330
5
0xc000056330
5
0xc000056330
5
指针的指针:
**ptr
go的切片
未指定大小的数组作为切片:
切片不需要说明长度,类似java中的Collection集合,或使用make函数来创建切片。
var identifier []type
var slice1 []type = make([]type, len)
// 也可以简写为
slice1 := make([]type, len)
常用函数:
len()
cap()
append()
copy()
go range
语法
// 切片
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
// map
//range也可以用在map的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
go map
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
go接口完整示例
package main
import "fmt"
func main() {
samsungPhone := samsung{"samsugn", "qua", "2440 * 1680", 312315456, []string{"zhangsan", "list"}}
samsungPhone.call(samsungPhone.phonenumber, samsungPhone.contractors[0])
}
type mobile interface {
call(number int64, man string) int64
play(game string)
}
type samsung struct {
brand string
cpu string
film string
phonenumber int64
contractors []string
}
func (samsungPhone samsung) call(number int64, man string) {
fmt.Println(samsungPhone.brand, "call ", man, " at ", number)
}
有疑问加站长微信联系(非本文作者)