##Day03 :

结构体和方法:

🔌面向对象:go语言仅支持封装,不支持继承和多态

结构的定义:
type TreeNode struct {
    Left, Right *TreeNode
    Value int
}

//切片定义
nodes := []treeNode{
		{value:3},
		{},
		{6,nil,&root},
	}

为结构定义方法:

func (node treeNode) print(){
    fmt.Println(node.value)
}

☑️Go语言虽然没有构造函数一说,但是可以通过工厂函数来控制。

func createNode(value int) *treeNode{
    return &treeNode{value:value}
}
使用指针作为方法接收者:
func (node *treeNode)setValue(value int){
    node.value=value
}

⚠️由于结构体是值传递,不存在引用传递。所以只有使用指针才可以改变结构内容。另:nil指针也可以调用方法。

遍历结构函数:

接上述代码。定义一个树结构,并向其各个节点赋值:

    var root treeNode
    root = treeNode{value:3}
    root.left = &treeNode{}
    root.right = &treeNode{5,nil,nil}
    root.right.left = new(treeNode)
    root.left.right = createNode(2)
    root.right.left.setValue(4)

中序遍历结构方法:

func (node *treeNode)Traverse(){		//定义一个Traverse函数,函数接收者是指针类型的一个node
if node == nil{
return   
}   
node.left.Traverse()
node.print()
node.right.Traverse()
}

中序遍历结构函数打印结果


包和封装:

定义:

首字母大写:public

首字母小写:private

⚠️为一个结构定义的方法需要在同一个包内

后序遍历结构函数:

type myTreeNode struct {
    node *tree.Node
}
func (myNode *myTreeNode) postOrder(){		//定义一个postOrder()函数,函数接收者是一个指针类型的myNode
    if myNode == nil || myNode.node == nil{
        return   
    }   
    //左右子树节点初始化
    left := myTreeNode{myNode.node.Left}	
    left.postOrder()
    right := myTreeNode{myNode.node.Right}
    right.postOrder()
    myNode.node.Print()
}

后序遍历结构函数打印结果


接口:

接口定义:
type Retriever interface {
    Get(url string) string
}

func download (r Retriever) string{
    return r.Get("http://www.baidu.com")
}

🦆“duck typing” 接口实现是隐式的,只要实现接口里的方法就行。

接口的组合:

一个接口中可以整合其他接口或者方法

type RetrieverPoster interface {
    Retriever
    Poster
    Connect(host string)
}

func session(r RetrieverPoster){
    r.Get()
    r.setValue()
}

函数式编程:

举例:

func adder() func(int)int{		//定义adder()函数,类型是带有一个int参数,返回值是int的函数
    sun := 0
    return func (v int)int{
        sun += v
        return sun
    }
}

func main(){
    a := adder()
    for i := 0; i < 10; i++{
        fmt.Println(a(i))
    }
}

使用函数方法来遍历二叉树:

//重新定义一个遍历函数,与之前定义的Traverse函数不同,这里的TraverseFunc函数带有的参数是一个结构函数
func (node *Node) TraverseFunc(f func(*Node)){
    if node == nil{
        return   
    }
    node.Left.TraverseFunc(f)	//这里f就是带有一个*Node参数的结构函数
    f(node)		
    node.Right.TraverseFunc(f)
}
//修改后的遍历函数
func (node *Node) Traverse(){	
	node.TraverseFunc(func (n *Node){   //在函数体里调用重新定义好的函数
		n.Print()
	})
}

🕶至此,相较于定义函数来遍历二叉树,函数方法可以干的事情就更多了,而不局限于运行写好的函数体内容。

//在main()函数里可以添加节点计数器,直接调用重新定义的函数就可以了,十分简便!
nodeCount := 0
root.TraverseFunc(func (*tree.Node){
    nodeCount ++
})
fmt.Println("nodeConut:",nodeCount)

##Day04 :

defer调用 :

🌓defer关键字有几个特点:

*确保调用在函数结束时发生

*参数在defer语句时计算

*defer列表为先进后出

//确保调用在函数结束时发生
file,err := os.Create(filename) 
if err != nil{
   panic(err)   
}
defer file.Close()  

writer := bufio.NewWriter(file) 
defer writer.Flush()
func tryDefer(){
    for i := 0 ;i < 100; i++{
        defer fmt.Println(i)
        if i==30{
            panic ("print too many!")
        }   
    }
}
func main(){
    tryDefer()
}

参数在defer语句时计算

对于错误处理要看文档

panic :

*停止当前函数执行

*一直向上返回,执行每一层的defer

*如果没有遇见recover,程序退出

recover :

*仅在defer调用中使用

*获取panic的值

*如果无法处理,可重新panic

func tryRecover(){   defer func(){
    //匿名函数,只用写函数体
    r := recover()
    if err,ok := r.(error);ok{
        fmt.Println("Error occurred",err)
    }else {
        panic(fmt.Sprintf("I dont know what to do : %v",r))
    }   
}()          //匿名函数所带参数
        panic(errors.New("This is an error"))
                  //a := 5/5   
                  //fmt.Println(a)
                  panic(123)
                 }
func main() {
    tryRecover()
} 

panic&amp;recover



Go

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!