1、返回多个值
- 函数或方法中返回超过四五个值的情况时,如果这些值是同一类型的话最好
使用一个切片来传递,如果其值类型各异则最好传递一个指向结构体的指针。
- 传递一个切片或一个指向结构体的指针的成本都比较低(在64位的机器上一个切片占16位,一个映射占8字节),同时也允许我们修改数据
2、数组、切片
- 数组是定长的 a := [3]int{1,2,3}/a := [...]int{1,2,3} ,[...]会自动计算数组长度
- 切片长度不定 b := []int
区别
- 数组是值传递,而切片是引用传递
- 在go的标准库中的所有公开函数中使用的都是切片而非数组,建议使用切片
- 创建一个切片时,会创建一个隐藏的初始化为零值的数组,然后返回一个引用该隐藏数组的切片。所以切片其实就是一个隐藏数组的引用
- 若底层数组,修改值,则引用其数组的相关切片,对应的值也会改变,更改切片其实都是对底层的隐藏数据进行了修改
3、interface类型断言
switch x.(type){//type为关键字而非一个实际类型,用于表示任意类型
case bool:
fmt.Printf("param #%d is a bool\n", i)
case float64:
fmt.Printf("param #%d is a float64\n", i)
case int, int8, int16, int32, int64:
fmt.Printf("param #%d is a int\n", i)
case uint, uint8, uint16, uint32, uint64:
fmt.Printf("param #%d is a unsigned int\n", i)
case nil:
fmt.Printf("param #%d is a nil\n", i)
case string:
fmt.Printf("param #%d is a string\n", i)
default :
fmt.Printf("param #%d's type is unknow\n", i)
}
4、泛型函数
- 参数声明为interface{}类型,结合接口类型断言,switch,根据传入的参数的类型,设计不同的逻辑
在一个切片中查找某一项的索引
func Index(xs interface{}, x interface{}) int {
switch slice := xs.(type) {
case []int:
for i,y := range slice{
if y == x.(int){
return i
}
}
case []string:
for i, y := range slice{
if y == x.(string) {
return i
}
}
}
return -1
}
5、可变长参数
package main
import "fmt"
// 这个函数可以传入任意数量的整型参数
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
// 支持可变长参数的函数调用方法和普通函数一样
// 也支持只有一个参数的情况
sum(1, 2)
sum(1, 2, 3)
// 如果你需要传入的参数在一个切片中,像下面一样
// "func(slice...)"把切片打散传入
nums := []int{1, 2, 3, 4}
sum(nums...)
}
6、关于go文件目录
- src下建立 project ,project 中包含main.go、其他包文件- 。 src:{project : { main.go, otherpackage}}
7、struct{} 几种特殊用法
空结构体,不占用内存,地址不可变
1、用于改造长set
- 声明 map[string]struct{},由于struct{}是空,不关心内容,这样map便改造为set
2、用于传递信号的通道,关于非缓存的通道,需要close后,才可以接触阻塞