设为首页 加入收藏

TOP

go 语言学习笔记(三)
2019-07-25 14:18:22 】 浏览:323
Tags:语言学习 笔记
会引起程序的崩溃,因此panic一般用于严重错误,如程序内部的逻辑不一致。

Recover捕获异常

如果在deferred函数中调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,recover会使程序从panic中恢复,并返回panic value。导致panic异常的函数不会继续运行,但能正常返回。在未发生panic时调用recoverrecover会返回nil。

func Parse(input string) (s *Syntax, err error) {
defer func() {
if p := recover(); p != nil {
err = fmt.Errorf("internal error: %v"
, p)
}
}()
// ...parser...
}

deferred函数帮助Parse从panic中恢复。在deferred函数内部,panic value被附加到错误信息中;并用err变量接收错误信息,返回给调用者。我们也可以通过调用runtime.Stack往错误信息中添加完整的堆栈调用信息。

方法

GO不支持类,但支持方法,可以为结构体或其他类型定义方法,方法就是一类带特殊的 接收者 参数的函数。方法接收者在它自己的参数列表内,位于 func 关键字和方法名之间。

type Vertex struct {
    X, Y float64
}
  
  func (v Vertex) Abs() float64 {        //定义结构体方法
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
  }
  
  func main() {
    v := Vertex{3, 4}
      fmt.Println(v.Abs())                  //v.Abs() 调用方法
  }

其形式类似于将函数声明中的形参放到函数名之前

只能为同一个包的类型接收者声明方法,不能为其他包内定义的类型声明方法

可以为其他类型定义方法,但不能为内置类型(如:int)定义方法

  type MyFloat float64
  
  func (f MyFloat) Abs() float64 {              //ture
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
  }
  //cannot define new methods on non-local type float64
  //func (f float64) Abs() float64 {       
  //    if f < 0 {
  //        return float64(-f)
  //    }
  //    return float64(f)
  //}
  
  
  
  func main() {
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs())
  }
  

指针接收者

使用指针接收者可以改变接收者自身的值

type Vertex struct {
    X, Y float64
}

func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {               //指针接收者
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    v.Scale(10)                 //v = {30,40}
    fmt.Println(v.Abs())
}

调用函数时,指针类型的形参必须接受一个指针;调用方法时接收者为变量时可以是指针也可以为值,编译器会自动解引用或取地址。

var v Vertex
ScaleFunc(v, 5)  // 编译错误!
ScaleFunc(&v, 5) // OK

var v Vertex
v.Scale(5)  // OK
p := &v
p.Scale(10) // OK

在现实的程序里,一般会约定如果Point这个类有一个指针作为接收器的方法,那么所有Point 的方法都必须有一个指针接收器,即使是那些并不需要这个指针接收器的函数。

只有类型(Point)和指向他们的指针(*Point),才是可能会出现在接收器声明里的两种接收器。 此外,为了避免歧义,在声明方法时,如果一个类型名本身是一个指针的话,是不允许其出现在接收器中的,比如下面这个例子:

type    P   *int 
func    (P) f() {   /*  ... */  }   //  compile error:  invalid receiver    type
  1. 不管你的method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型 进行调用的,编译器会帮你做类型转换。
  2. 在声明一个method的receiver该是指针还是非指针类型时,你需要考虑两方面的内部,第 一方面是这个对象本身是不是特别大,如果声明为非指针变量时,调用会产生一次拷贝;第二方面是如果你用指针类型作为receiver,那么你一定要注意,这种指针类型指向 的始终是一块内存地址,就算你对其进行了拷贝。熟悉C或者C艹的人这里应该很快能明 白

使用嵌入类型扩展类型

使用嵌入结构体时,被嵌入结构体可以直接调用嵌入结构体的方法,

import "image/color"
type Point struct{ X, Y float64 }
type ColoredPoint struct {
    Point
    Color color.RGBA
}

red := color.RGBA{255, 0, 0, 255}
blue := color.RGBA{0, 0, 255, 255}
var p = ColoredPoint{Point{1, 1}, red}
var q = ColoredPoint{Point{5, 4}, blue}
fmt.Println(p.Distance(q.Point)) // "5"   Distance是point类型的方法,p的类型为ColoredPoint,但可以直接调用Distance
p.ScaleBy(2)
q.ScaleBy(2)
fmt.Println(p.Distance(q.Point)) // "10" 但参数类型为Point时,必须显示调用point字段

方法值和方法表达式

可以将特定变量的方法调用赋值给变量,通过变量调用方法,其形式类似于函数变量的赋值:

p := Point{1, 2}
q := Point{4, 6}
distanceFromP := p.Distance // method value,选择器返回一个方法值
fmt.Println(distanceFromP(q)) // "5"

scaleP := p.ScaleBy // method value,选择器返回一个方法值
scaleP(2) // p becomes (2, 4)

p.distancep.ScaleBy称为选择器,选择器返回一个方法值。

在一个包的API需要一个函数值、且调用方希望操作的是某一个绑定了对象的方法的话,方
法"值"会非常实用。举例来说,下面例子中的time.AfterFunc这个函数的功能是在指定的延迟时间之后来执行一个(译注:另外的)函数。且这个函数操作的是一个Rocket对象r

type Rocket struct { /* ... */ }
func (r Rocket) Launch() { / ... */ }
r := new(Rocket)
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Golang-使用mysql 下一篇[系列] Gin 框架 - 安装和路由配置

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目