##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()
}
对于错误处理要看文档
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()
}
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!