go代码知识点整理

目录

    • 1. 取两数之间的随机数
    • 2. time.After
    • 3. sort.sort实现自定义排序(此部分转载)
    • 4. 进制
    • 5. 字符串处理
      • 5.1 输入输出
      • 5.2 ASCII
      • 字符串反转、切片反转
    • 6. math基本数学函数
    • 7. 取调用函数名和调用者的方法名
    • 8. map
      • 8.1 golang中,map作为函数参数是如何传递的
      • 8.2 读取json文件并解析成map
    • 9. slice切片中的坑!
    • 10. go操作文件
    • 11.append:函数返回值地址无法引用

1. 取两数之间的随机数

//取[left,right内的随机整数]
func genRand(left,right int)int {
    random.Seed(time.Now().UnixNano())
    return random.Intn(right-left+1)+left 
    //[0,right-left+1)+left=[left,right+1)
}

2. time.After

可用于实现超时控制
https://studygolang.com/articles/13045?fr=sidebar

// After waits for the duration to elapse and then sends the current time
// on the returned channel.
// It is equivalent to NewTimer(d).C.
// The underlying Timer is not recovered by the garbage collector
// until the timer fires. If efficiency is a concern, use NewTimer
// instead and call Timer.Stop if the timer is no longer needed.
func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

中文解释:
https://www.cnblogs.com/qggg/p/8571808.html

3. sort.sort实现自定义排序(此部分转载)

排序算法
该包实现了四种基本排序算法:插入排序、归并排序、堆排序和快速排序。 但是这四种排序方法是不公开的,它们只被用于sort包内部使用。所以在对数据集合排序时不必考虑应当选择哪一种排序方法,只要实现了sort.Interface定义的三个方法:获取数据集合长度的Len()方法、比较两个元素大小的Less()方法和交换两个元素位置的Swap()方法,就可以顺利对数据集合进行排序。sort包会根据实际数据自动选择高效的排序算法。 除此之外,为了方便对常用数据类型的操作,sort包提供了对[]int切片、[]float64切片和[]string切片完整支持,主要包括:

  • 对基本数据类型切片的排序支持
  • 基本数据元素查找
  • 判断基本数据类型切片是否已经排好序
  • 对排好序的数据集合逆序

数据集合排序(如结构体)
前面已经提到过,对数据集合(包括自定义数据类型的集合)排序需要实现sort.Interface接口的三个方法,我们看以下该接口的定义:

type Interface interface {
		// 获取数据集合元素个数
		Len() int
		// 如果i索引的数据小于j所以的数据,返回true,不会调用
		// 下面的Swap(),即数据升序排序。
		Less(i, j int) bool
		// 交换i和j索引的两个元素的位置
        Swap(i, j int)
}

数据集合实现了这三个方法后,即可调用该包的Sort()方法进行排序。 Sort()方法定义如下:

func Sort(data Interface)

Sort()方法惟一的参数就是待排序的数据集合。

该包还提供了一个方法可以判断数据集合是否已经排好顺序,该方法的内部实现依赖于我们自己实现的Len()和Less()方法:

func IsSorted(data Interface) bool {
    n := data.Len()
    for i := n - 1; i > 0; i-- {
        if data.Less(i, i-1) {
            return false
        }
    }
    return true
}

下面是一个使用sort包对学生成绩排序的示例:

package main

import (
	"fmt"
	"sort"
)

//学生成绩结构体
type StuScore struct {
     //姓名
    name  string
    //成绩
    score int
}

type StuScores []StuScore

//Len()
func (s StuScores) Len() int {
	return len(s)
}

//Less():成绩将有低到高排序
func (s StuScores) Less(i, j int) bool {
	return s[i].score < s[j].score
}

//Swap()
func (s StuScores) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func main() {
    stus := StuScores{
                {"alan", 95},
                {"hikerell", 91},
                {"acmfly", 96},
                {"leao", 90}}

    fmt.Println("Default:")
    //原始顺序
    for _, v := range stus {
        fmt.Println(v.name, ":", v.score)
    }
    fmt.Println()
    //StuScores已经实现了sort.Interface接口
    sort.Sort(stus)
    
    fmt.Println("Sorted:")
     //排好序后的结构
    for _, v := range stus {
        fmt.Println(v.name, ":", v.score)
    }

    //判断是否已经排好顺序,将会打印true
    fmt.Println("IS Sorted?", sort.IsSorted(stus))
}

程序该示例程序的自定义类型StuScores实现了sort.Interface接口,所以可以将其对象作为sort.Sort()和sort.IsSorted()的参数传入。运行结果:

======Default======
alan : 95
hikerell : 91
acmfly : 96
leao : 90

======Sorted=======
leao : 90
hikerell : 91
alan : 95
acmfly : 96
IS Sorted? true

该示例实现的是升序排序,如果要得到降序排序结果,其实只要修改Less()函数:

//Less():成绩降序排序,只将小于号修改为大于号
func (s StuScores) Less(i, j int) bool {
	return s[i].score > s[j].score
}

此外,sort包提供了Reverse()方法,可以允许将数据按Less()定义的排序方式逆序排序,而不必修改Less()代码。方法定义如下:

func Reverse(data Interface) Interface

我们可以看到Reverse()返回的一个sort.Interface接口类型,整个Reverse()的内部实现比较有趣:

//定义了一个reverse结构类型,嵌入Interface接口
type reverse struct {
    Interface
}

//reverse结构类型的Less()方法拥有嵌入的Less()方法相反的行为
//Len()和Swap()方法则会保持嵌入类型的方法行为
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

//返回新的实现Interface接口的数据类型
func Reverse(data Interface) Interface {
    return &reverse{data}
}

了解内部原理后,可以在学生成绩排序示例中使用Reverse()来实现成绩升序排序:

sort.Sort(sort.Reverse(stus))
 for _, v := range stus {
    fmt.Println(v.name, ":", v.score)
}

最后一个方法:Search()

func Search(n int, f func(int) bool) int

官方文档这样描述该方法:

Search()方法回使用“二分查找”算法来搜索某指定切片[0:n],并返回能够使f(i)=true的最小的i(0<=i i之前的切片元素会使f()函数返回false,i及i之后的元素会使f()函数返回true。但是,当 在切片中无法找到时f(i)=true的i时(此时切片元素都不能使f()函数返回true),Search() 方法会返回n。

Search()函数一个常用的使用方式是搜索元素x是否在已经升序排好的切片s中:

x := 11
s := []int{3, 6, 8, 11, 45} //注意已经升序排序
pos := sort.Search(len(s), func(i int) bool { return s[i] >= x })
if pos < len(s) && s[pos] == x {
    fmt.Println(x, "在s中的位置为:", pos)
} else {
    fmt.Println("s不包含元素", x)
}

官方文档还给出了一个猜数字的小程序:

func GuessingGame() {
	var s string
	fmt.Printf("Pick an integer from 0 to 100.\n")
	answer := sort.Search(100, func(i int) bool {
		fmt.Printf("Is your number <= %d? ", i)
		fmt.Scanf("%s", &s)
		return s != "" && s[0] == 'y'
	})
	fmt.Printf("Your number is %d.\n", answer)
}

sort包已经支持的内部数据类型排序
sort包原生支持[]int、[]float64和[]string三种内建数据类型切片的排序操作,即不必我们自己实现相关的Len()、Less()和Swap()方法。

  1. IntSlice类型及[]int排序

由于[]int切片排序内部实现及使用方法与[]float64和[]string类似,所以只详细描述该部分。

sort包定义了一个IntSlice类型,并且实现了sort.Interface接口:

type IntSlice []int
func (p IntSlice) Len() int           { return len(p) }
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
//IntSlice类型定义了Sort()方法,包装了sort.Sort()函数
func (p IntSlice) Sort() { Sort(p) }
//IntSlice类型定义了SearchInts()方法,包装了SearchInts()函数
func (p IntSlice) Search(x int) int { return SearchInts(p, x) }

并且提供的sort.Ints()方法使用了该IntSlice类型:

func Ints(a []int) { Sort(IntSlice(a)) }

所以,对[]int切片排序是更常使用sort.Ints(),而不是直接使用IntSlice类型:

s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
sort.Ints(s)
fmt.Println(s) //将会输出[1 2 3 4 5 6]

如果要使用降序排序,显然要用前面提到的Reverse()方法:

s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s) //将会输出[6 5 4 3 2 1]

如果要查找整数x在切片a中的位置,相对于前面提到的Search()方法,sort包提供了SearchInts():

func SearchInts(a []int, x int) int

注意,SearchInts()的使用条件为:切片a已经升序排序

s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
sort.Ints(s) //排序后的s为[1 2 3 4 5 6]
fmt.Println(sort.SearchInts(s, 3)) //将会输出2
  1. Float64Slice类型及[]float64排序

实现与Ints类似,只看一下其内部实现:

type Float64Slice []float64

func (p Float64Slice) Len() int           { return len(p) }
func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || isNaN(p[i]) && !isNaN(p[j]) }
func (p Float64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Float64Slice) Sort() { Sort(p) }
func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }

与Sort()、IsSorted()、Search()相对应的三个方法:

func Float64s(a []float64)
func Float64sAreSorted(a []float64) bool
func SearchFloat64s(a []float64, x float64) int
要说明一下的是,在上面Float64Slice类型定义的Less方法中,有一个内部函数isNaN()。 isNaN()与math包中IsNaN()实现完全相同,sort包之所以不使用math.IsNaN(),完全是基于包依赖性的考虑,应当看到,sort包的实现不依赖与其他任何包。

  1. StringSlice类型及[]string排序

两个string对象之间的大小比较是基于“字典序”的。

实现与Ints类似,只看一下其内部实现:

type StringSlice []string

func (p StringSlice) Len() int           { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p StringSlice) Sort() { Sort(p) }
func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }

与Sort()、IsSorted()、Search()相对应的三个方法:

func Strings(a []string) func StringsAreSorted(a []string) bool func
SearchStrings(a []string, x string) int

4. 进制

package main
 
import "fmt"
 
func main(){
	// 十进制
	var a int = 10
	fmt.Printf("%d \n", a)  // 10
	//二进制
	// 二进制不能直接去表示
	fmt.Printf("%b \n", a)  // 1010  占位符%b表示二进制
 
	// 八进制  以0开头
	var b int = 077
	fmt.Printf("%o \n", b)  // 77
 
	// 十六进制  以0x开头
	var c int = 0xff
	fmt.Printf("%x \n", c)  // ff
	fmt.Printf("%X \n", c)  // FF
 	
 	//地址
	fmt.Printf("%p \n", &a)  // 0xc00004c080  占位符%p表示十六进制的内存地址
}
 

5. 字符串处理

5.1 输入输出

输入不定长字符串后,回车:

    var a []byte
    fmt.Scanf("%s",&a)
    //aA
    //aA

输入包含空格的字符串,回车

//以回车为终止符,不保存终止符
 in := bufio.NewScanner(os.Stdin)
    if in.Scan() {
        a=in.Text()
    }
//以回车为终止符,保存终止符
in := bufio.NewReader(os.Stdin)
    a,_:=in.ReadBytes('\n')

5.2 ASCII

在这里插入图片描述

字符串反转、切片反转

//切片反转
func reverse(a []byte) []byte {
    for i,j:=0,len(a)-1;i<j;i,j=i+1,j-1{
        a[i],a[j]=a[j],a[i]
    }
    return a
}

//字符串反转
func Reverse(s string) string {
   r := []rune(s)
   for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
       r[i], r[j] = r[j], r[i]
   }
   return string(r)
}

6. math基本数学函数

三角函数
正弦函数,反正弦函数,双曲正弦,反双曲正弦

func Sin(x float64) float64
func Asin(x float64) float64
func Sinh(x float64) float64
func Asinh(x float64) float64

一次性返回sin,cos

func Sincos(x float64) (sin, cos float64)

余弦函数,反余弦函数,双曲余弦,反双曲余弦

func Cos(x float64) float64
func Acos(x float64) float64
func Cosh(x float64) float64
func Acosh(x float64) float64

正切函数,反正切函数,双曲正切,反双曲正切

func Tan(x float64) float64
func Atan(x float64) float64 和 func Atan2(y, x float64) float64
func Tanh(x float64) float64
func Atanh(x float64) float64

幂次函数

func Cbrt(x float64) float64 //立方根函数
func Pow(x, y float64) float64 // x的幂函数
func Pow10(e int) float64 // 10根的幂函数
func Sqrt(x float64) float64 // 平方根
func Log(x float64) float64 // 对数函数
func Log10(x float64) float64 // 10为底的对数函数
func Log2(x float64) float64 // 2为底的对数函数
func Log1p(x float64) float64 // log(1 + x)
func Logb(x float64) float64 // 相当于log2(x)的绝对值
func Ilogb(x float64) int // 相当于log2(x)的绝对值的整数部分
func Exp(x float64) float64 // 指数函数
func Exp2(x float64) float64 // 2为底的指数函数
func Expm1(x float64) float64 // Exp(x) - 1

特殊函数

func Inf(sign int) float64 // 正无穷
func IsInf(f float64, sign int) bool // 是否正无穷
func NaN() float64 // 无穷值
func IsNaN(f float64) (is bool) // 是否是无穷值
func Hypot(p, q float64) float64 // 计算直角三角形的斜边长

类型转化函数

func Float32bits(f float32) uint32 // float32和unit32的转换
func Float32frombits(b uint32) float32 // uint32和float32的转换
func Float64bits(f float64) uint64 // float64和uint64的转换
func Float64frombits(b uint64) float64 // uint64和float64的转换

其他函数

func Abs(x float64) float64 // 绝对值函数
func Ceil(x float64) float64 // 向上取整
func Floor(x float64) float64 // 向下取整
func Mod(x, y float64) float64 // 取模
func Modf(f float64) (int float64, frac float64) // 分解f,以得到f的整数和小数部分
func Frexp(f float64) (frac float64, exp int) // 分解f,得到f的位数和指数
func Max(x, y float64) float64 // 取大值
func Min(x, y float64) float64 // 取小值
func Dim(x, y float64) float64 // 复数的维数
func J0(x float64) float64 // 0阶贝塞尔函数
func J1(x float64) float64 // 1阶贝塞尔函数
func Jn(n int, x float64) float64 // n阶贝塞尔函数
func Y0(x float64) float64 // 第二类贝塞尔函数0阶
func Y1(x float64) float64 // 第二类贝塞尔函数1阶
func Yn(n int, x float64) float64 // 第二类贝塞尔函数n阶
func Erf(x float64) float64 // 误差函数
func Erfc(x float64) float64 // 余补误差函数
func Copysign(x, y float64) float64 // 以y的符号返回x值
func Signbit(x float64) bool // 获取x的符号
func Gamma(x float64) float64 // 伽玛函数
func Lgamma(x float64) (lgamma float64, sign int) // 伽玛函数的自然对数
func Ldexp(frac float64, exp int) float64 // value乘以2的exp次幂
func Nextafter(x, y float64) (r float64) //返回参数x在参数y方向上可以表示的最接近的数值,若x等于y,则返回x
func Nextafter32(x, y float32) (r float32) //返回参数x在参数y方向上可以表示的最接近的数值,若x等于y,则返回x
func Remainder(x, y float64) float64 // 取余运算
func Trunc(x float64) float64 // 截取函数

正无穷
var max = math.Inf(-1)
负无穷
var smax = math.Inf(-1)

7. 取调用函数名和调用者的方法名

package main

import(
    "fmt"
    "runtime"
)

// 获取正在运行的函数名
func runFuncName()string{
    //pc := make([]uintptr,1)
    //runtime.Callers(2,pc)
    //f := runtime.FuncForPC(pc[0])
    //return f.Name()
    pc, _, _, _ := runtime.Caller(1)
    return runtime.FuncForPC(pc).Name()
}

func main() {
    Foo()
}
func Foo() {
    fmt.Printf("我是 %s, %s 在调用我!\n", printMyName(), printCallerName())
    Bar()
}
func Bar() {
    fmt.Printf("我是 %s, %s 又在调用我!\n", printMyName(), printCallerName())
}
func printMyName() string {
    pc, _, _, _ := runtime.Caller(1)
    return runtime.FuncForPC(pc).Name()
}
func printCallerName() string {
    pc, _, _, _ := runtime.Caller(2)
    return runtime.FuncForPC(pc).Name()
}
//我是 main.Foo, main.main 在调用我!
//我是 main.Bar, main.Foo 又在调用我!

8. map

8.1 golang中,map作为函数参数是如何传递的

https://www.cnblogs.com/zhouj-happy/p/10962500.html

8.2 读取json文件并解析成map

https://www.jianshu.com/p/eb13d1028020

9. slice切片中的坑!

https://www.jianshu.com/p/354fce23b4f0
https://blog.csdn.net/u013536232/article/details/105547626
https://studygolang.com/topics/10399
https://www.jb51.net/article/136199.htm

10. go操作文件

http://c.biancheng.net/view/5729.html
O_RDONLY:只读模式打开文件;
O_WRONLY:只写模式打开文件;
O_RDWR:读写模式打开文件;
O_APPEND:写操作时将数据附加到文件尾部(追加);
O_CREATE:如果不存在将创建一个新文件;
O_EXCL:和 O_CREATE 配合使用,文件必须不存在,否则返回一个错误;
O_SYNC:当进行一系列写操作时,每次都要等待上次的 I/O 操作完成再进行;
O_TRUNC:如果可能,在打开时清空文件。

11.append:函数返回值地址无法引用

//不报错
x:=append((*nums)[:2],(*nums)[3:]...)
Backtracking(&x)
//报错
Backtracking(&append((*nums)[:2],(*nums)[3:]...))

go代码知识点整理_第1张图片

可能的原因:实际上,这可能是因为函数的返回值可能没有可用的地址;它可能在一个寄存器中(在这种情况下它肯定是不可寻址的)或在堆栈上(在这种情况下它有一个地址,但如果它被放入一个逃避当前范围的指针则无效.保证可寻址性,Go必须完全相当于将它分配给一个变量.但Go是一种语言,如果它要为一个变量分配存储,那将是因为你说,而不是因为编译器神奇地决定.因此它不会使函数的结果可寻址.

或者我可能过度思考它并且他们根本不想为返回一个值的函数与返回多个函数的函数有一个特殊情况:)
来源:http://www.voidcn.com/article/p-ayiiquzc-buc.html

你可能感兴趣的:(Golang,golang,算法)