练习:实现 Pic。它应当返回一个长度为 dy 的切片,其中每个元素是一个长度为 dx,元素类型为 uint8 的切片。当你运行此程序时,它会将每个整数解释为灰度值(好吧,其实是蓝度值)并显示它所对应的图像。https://tour.go-zh.org/moretypes/18
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
var pic = make([][]uint8, dy)//先申请行
for y := 0; y < dy; y ++{
for x := 0; x < dx; x ++ {
pic[y] = make([]uint8, dx)//在申请列
pic[y][x] = uint8(x * y)
}
}
return pic
}
func main() {
pic.Show(Pic)
}
练习:实现 WordCount。它应当返回一个映射,其中包含字符串 s 中每个“单词”的个数。函数 wc.Test 会对此函数执行一系列测试用例,并输出成功还是失败。https://tour.go-zh.org/moretypes/23
range
遍历一遍就是。package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
var wc = make(map[string]int)
for _,v := range strings.Fields(s) {
if _, ok := wc[v]; ok == true {
wc[v]++
} else {
wc[v] = 1
}
}
return wc
}
func main() {
wc.Test(WordCount)
}
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
//hypot等于一个参数是两个浮点数下x,y,返回值也是浮点数的函数,函数是求x,y的平方和的平方根
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
//所以给hypot()传5,12得出13
fmt.Println(hypot(5, 12))
//compute的第一个参数是一个参数是两个浮点数,返回值是浮点数的函数fn,本身的返回值是fn的返回值,及浮点数。return的时候fn里的参数是3,4
//当下面语句执行时,compute调用,fn等于hypot,在调用hypot等于的函数,并且参数是3,4,结果为5
fmt.Println(compute(hypot))
//这次fn等于Pow,求x的y次方,3的4次方结果81
fmt.Println(compute(math.Pow))
}
pos,neg := adder(), adder()
之后pos, neg
还是一个函数,但是前面的sum
已经申明过一次了,就存在在那里了,后面每一次的pos(i)
就是调用一次里面闭包,sum
就把每次的x
累加起来了。package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
输出结果是:
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90
练习:实现一个 fibonacci 函数,它返回一个函数(闭包),该闭包返回一个斐波纳契数列 (0, 1, 1, 2, 3, 5, ...)
。
f := fibonacci()
后留下f1,f2
,然后f()
重复10次,相当于重复f1, f2 = f2, (f1 + f2)
10次。package main
import "fmt"
// 返回一个“返回int的函数”
func fibonacci() func() int {
f1,f2 := 0, 1
return func() int {
f1, f2 = f2, (f1 + f2)
return f2 - f1
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Go里面还有几个方法可以实现Fibonacci,用通道的比较特别,到时候加上。
推荐看看这个帖子链接。
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
// 此方法表示类型 T 实现了接口 I,但我们无需显式声明此事。
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()//输出hello
}
接口也是值。它们可以像其它值一样传递。接口值可以用作函数的参数或返回值。
在内部,接口值可以看做包含值和具体类型的元组:
(value, type)
接口值保存了一个具体底层类型的具体值。接口值调用方法时会执行其底层类型的同名方法。
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("" )
return
}
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}//T的M()是在T的指针类型下实现的,所以要加&,不然会报错
describe(i)
i.M()
i = F(math.Pi)//i 是一个接口值,可以等于任意类型,所以之前等于结构体T,这里又可以等于F
describe(i)
i.M()
//底层值为nil的接口值
var t *T//t是nil
i = t
describe(i)//输出的时候%v是,但是类型并不是nil
i.M()
var i1 I//nil接口值
describe(i1)//输出两个nil
i1.M()//这里就该报panic了,这里的接口值本身就是nil,既不保存值也不保存具体类型
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
输出结果:
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
(<nil>, *main.T)
<nil>
(<nil>, <nil>)
panic: runtime error: invalid memory address or nil pointer dereference
指定了零个方法的接口值被称为 空接口:
interface{}
空接口可保存任何类型的值。(因为每个类型都至少实现了零个方法。)空接口被用来处理未知类型的值。
Log(str)
。但是这三个…不懂什么意思,好像是go的语法糖?。留个坑func Log(v ...interface{}) {
fmt.Println(v...)
}
类型断言 提供了访问接口值底层具体值的方式。
t, ok := i.(T)
这个写法和判断Map是否存在一个元素差不多v, ok := map[k]
switch v := i.(type) {
case T:
// v 的类型为 T
case S:
// v 的类型为 S
default:
// 没有匹配,v 与 i 的类型相同
}
先记录这么多,还有很多没有明白的地方。