go语言入门之-函数和方法

栏目: Go · 发布时间: 5年前

内容简介:函数生成包含函数的名字,形参列表,返回值列表(可选)以及函数体构成.需要注意一下几点:通过在参数列表最后的类型名称之前使用省略号来声明一个变长函数声明.

函数生成包含函数的名字,形参列表,返回值列表(可选)以及函数体构成.

func name(parameter-list) (result-list) {
  body
}
复制代码

需要注意一下几点:

  1. 函数的形参列表和返回值列表组成函数的签名,函数的签名会在函数被调用的时候做校验是否调用合法.

  2. 参数的传递是按值传递的.

  3. 支持多返回值.

  4. 函数变量是有类型的,不符合函数签名类型的调用会报错

    func changeArr(a [3]int) {
       a[0] = 100
     }
     func getArr(a [3]int) (int, int) {
         return a[0], a[1] // 多返回值
     }
     func main() {
       test := [3]int{1,2,3}
       changeArr(test)
       fmt.Println(test[0]) // 1 数组是基本类型 值传递不会改变原数组
       a, b := getArr(test); // 1, 2
     }
     // 当形参的基本类型的时候,不会修改外部的值.当形参是引用类型的时候,有可能会修改外部的值.
    复制代码

变长函数声明

通过在参数列表最后的类型名称之前使用省略号来声明一个变长函数声明.

func log(vals ...int) {
  for _, value := range vals {
    fmt.Println(value)
  }
}
func main() {
  b := []int{1,2,3}
  log(b...) // 1, 2, 3
  log(1,2,3) // 1, 2, 3
}
复制代码

函数变量(匿名函数)

通过在func关键字后不指定函数的名字可以声明函数变量,这种方式函数能获取整个词法环境(外部的变量).

func add() func() int {
  var x int;
  return func() int {
    x++
    return x
  }
}
func main() {
  f := add()
  fmt.Println(f()) // 1
  fmt.Println(f()) // 2
}
复制代码

错误处理机制

go语言通过普通的值来报告错误.常规的错误是开发者可以预见并且决定错误的行为的.这样得到的错误信息由于没有相应的堆栈信息而更加清晰.

错误传递

调用者在调用函数发生错误的时候,在错误信息上添加更多的调用信息传递给上层.

func test2()([]int, error) {
  return nil, errors.New("test2")
}
func test1() ([]int, error) {
  ret, err := test2()
  if err != nil {
    return nil, fmt.Errorf("test1 call test2 %v", err)
  }
  return ret, nil;
}
func main() {
  _, err := test1()
  fmt.Println(err); // test1 call test2 test2
}
复制代码

defer

defer语句是普通的函数调用,defer语句能确保函数的return语句或函数执行完毕之后执行对应的defer函数.

func log() func() {
  fmt.Println("start")
  return func() { fmt.Println("end") }
}
func main() {
  defer log()()
  fmt.Println("test defer")
}
// 输出 start test defer end
复制代码

注意点

  1. defer执行匿名函数会获取当前的词法环境,有可能修改函数执行的结果.

  2. defer语句能保证函数执行完执行,某些情况会导致资源无法释放.

    func readFills (filenams []string) {
       for _, filename := range filenams {
         f, err := os.Open(filename)
         defer f.Close()
       }
     }
     // 上面的例子会导致文件描述符被消耗无法释放,可以在进行单独的封装来控制defer对资源的释放.  
    复制代码

方法

方法声明

方法是声明特定类型(对象)上可以执行的函数. 通常可以使用如下的方式声明:

func (p structName) funcName(parameter-list) (result-list) {
  body
}  
// p 特定的类型(接受者)  声明可以在p类型上调用funcName的方法 
复制代码

注意:

  1. 由于方法的调用是p.funcName和获取p结构体上的属性一致,要注意同一类型上的命名冲突.

指针接收者方法

由于方法会复制实参,当需要方法的调用对外界产生影响的时候,就需要通过指针类型来完成方法的声明,如下面的例子:

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10} // 获取指针
  p.ScaleBy(2) // p{20, 20}
  q := Point{1,2}
  q.ScaleBy(3)  // q{3,6} 当类型符合的时候,会进行隐式转换 相当于 (&q).ScaleBy(3)
}  
复制代码

方法变量和方法表达式

方法变量

可以将一个特定类型的方法赋值给一个变量,这个变量称为方法变量.该方法变量已绑定到特定的接收者上(caller),通过传递形参就可以完成方法的调用.通常用于绑定特定的接受者.

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10}
  scaleBy := p.ScaleBy
  scaleBy(2) // p{20, 20}
}  
复制代码

方法表达式

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10}
  scaleBy := (*Point).ScaleBy // 方法表达式
  scaleBy(p,2)
}复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First Servlets & JSP(中文版)

Head First Servlets & JSP(中文版)

(美)巴萨姆、(美)塞若、(美)贝茨 / 苏钰函、林剑 / 中国电力出版社 / 2006-10 / 98.00元

《Head First Servlets·JSP》(中文版)结合SCWCD考试大纲讲述了关于如何编写servlets和JSP代码,如何使用JSP表达式语言,如何部署Web应用,如何开发定制标记,以及会话状态、包装器、过滤器、企业设计模式等方面的知识,以一种轻松、幽默而又形象的方式让你了解、掌握servlets和JSP,并将其运用到你的项目中去。《Head First Servlets·JSP》(中......一起来看看 《Head First Servlets & JSP(中文版)》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具