Duck Typeing & Interface
Duck Typing
Duck typing in computer programming is an application of the duck test -- "if it walks like a duck and it quacks like a duck, then it must be a duck"
Duck Typing in py
def duck_test(duck):
try:
duck.quack()
duck.walk()
except (AttributeError, TypeError):
print("can't quack()")
Duck Typing in java
Duck Typing in Go
非侵入式 Interface
非侵入式:不需要显示声明
当结构体的方法是某个接口的超集的时候 就可以认为该结构体实现了某接口
好处:降低耦合度 增加了可扩展性
package main
type person struct {
name string
}
func (p person)sing() {
fmt.Printf(p.name,"sing")
}
func (p person)dance() {
fmt.Printf(p.name,"dance")
}
func (p person)rap() {
fmt.Printf(p.name,"rap")
}
func (p person)playBasketball() {
fmt.Printf(p.name,"playBasketball")
}
func (p person)playSoccer() {
fmt.Printf(p.name,"playSoccer")
}
func (p person)fly() {
fmt.Printf(p.name,"fly")
}
func show(t Trainee) {
t.sing()
t.dance()
t.rap()
t.playBasketball()
}
type Trainee interface {
sing()
dance()
rap()
playBasketball()
}
func play(p Player){
p.playBasketball()
p.playSoccer()
}
type Player interface{
playBasketball()
playSoccer()
}
func showOff(superman Superman){
superman.fly()
}
type Flyer interface {
fly()
}
// 组合接口
type Superman interface {
Flyer
Trainee
}
func main() {
joey := person("joey")
show(joey)
play(joey)
showOff(joey)
}
Memory Allocation and Escape Analysis
Go内存分配与逃逸分析
堆栈内存
- 堆Heap
- 可以动态分配内存大小,适合不可预知大小的内存分配
- 声明周期享有自主控制权
- 复杂的内存管理会占用资源 速度慢 存在内存碎片已经内存泄露问题
- 栈Stack
- 存取数据要比堆快很多
- 缺乏灵活性 栈中数据大小与编译器挂钩 生命周期是确定的
- 与函数共存亡
逃逸分析Escape Analysis
根据堆栈数据存储不同的特点,需要对程序中的数据选择合适的区域进行存放。
GC语言将堆栈内存的分配对于程序员变的透明。逃逸分析就是编译器能分析代码特征决定数据应该用堆还是栈来进行内存分配。
JVM也可以通过参数开启逃逸分析
逃逸失败案例:
栈中变量a在函数结束的时候会被弹栈 地址空间不存在
#include <stdio.h>
int *returnArr(){
int a = 3;
return &a;
}
int main() {
return 0;
}
go中编译器做的逃逸分析
package main
func returnArr() *int{
a:=3
return &a
}
func main() {
}
go build -gcflags '-m -l' main.go
查看内存逃逸情况
go tool compile -S main.go
查看局部变量是否真的进入heap中runtime.newObject(SB)
package main
func returnArr() *int{
a := new(int)
return a // new 默认返回指针
}
func main() {
}
不引发逃逸行为
package main
func returnArr() int{
a := new(int) // 取决于上下文的环境 来觉得是否又必要去堆还是栈中申请内存
// 取决于变量是否会被函数外部引用
return *a // 不会引发逃逸行为
}
func main() {
}
go tool compile -S main.go
查看发现没有去堆中申请内存的操作
Go Closure闭包
Closure: 关闭,倒闭,道路封闭
闭包:
- 函数可以作为值传递
f := funcA
,f := funcA()//接受返回值
- 词法作用域,编写代码时确定的作用域,是静态的作用域。外部函数无法直接访问函数的局部变量
函数+函数内部的引用环境
示例:
package main
import "fmt"
func enemy() func() {
key := 0
return func() {
key++
fmt.Println(key)
}
}
func main() {
f := enemy() // 返回匿名函数func 以及函数内部的引用环境 key
f() // 1
f() // 2
f() // 3
f() // 4
}
Function Currying(函数柯里化)
- 分阶段接受参数
- 参数的复用 分阶段执行
package main
func adder(a, b int) {
fmt.Println(a + b)
}
func curryAdder(a int) func(int) {
return func(b int) {
fmt.Println(a + b)
}
}
func main() {
adder(1, 2) // 一次执行到位 a + b
addB := curryAdder(1) // => 1 + b, b还没有传入参数
fmt.Println("wait")
addB(2) // => 1 + 2
addB(3) // => 1 + 3, 1被复用
}
闭包存在内存泄露的风险 谨慎使用