乐趣区

关于golang:跟着老猫来搞GO基础进阶

回顾一下上一篇博客,次要是和大家分享了 GO 语言的根底语法,其中蕴含变量定义,根本类型,条件语句,循环语句。那本篇呢就开始和大家同步一下 GO 语言根底的进阶。

函数的定义

上次其实在很多的 DEMO 中曾经写进去一些函数了,然而没有讲清楚其函数定义。接下来咱们同样地要举例说明一下,间接看代码。

func calculate(a,b int, op string) int {
    switch op {
    case "+":
        return a + b
    case "-":
        return a - b
    case "*":
        return a * b
    case "/":
        return a / b
    default:
        panic("unsupported op")
    }
}

以上是一个比较简单的计算两个整数加减乘除运算的一个函数,首先咱们能够看到的是函数的定义其实也是遵循着变量的定义形式,咱们先定义函数的名称,而后才是函数的返回值。当然函数中的参数定义也是如此。

除此以外,其实 GO 语言绝对于其余语言来说有一个比拟骚的操作,就是他能够存在多个返回值。例如上面咱们写一个除法的例子,就是大家小学就学过的除不尽的时候存在余数的状况。上面咱们来看一个函数。

func div(a int, b int) (int,int){return a / b, a % b}

大家看到下面这个返回值有什么感想,其实这最终的两个返回值是没有体现任何业务意义的,咱们无奈辨别最终返回的后果到底是干什么用的。当然 GO 语言其实也发现了这个弊病,所以呢,咱们的返回值的名称也是能够定义的,具体如下,咱们命名除法失去的商为 q,余数为 r,那么咱们改良之后就失去如下:

func div(a int, b int) (q ,r int){return a / b, a % b}

如果这样的话咱们 main 调用失去后果就能够这么获取

func main() {fmt.Println(div(4,3))
    q,r := div(5,6)
    fmt.Println(q,r)
}

那么此时问题又来了,如果咱们只有其中的一个商,余数不要,这又是如何写呢,因为咱们都晓得 go 的语法中,定义进去的变量前面都得用到才行,否则的话会报编译谬误,那其实咱们间接用 ”_” 来替换即可。具体代码块如下

func main() {q,_ := div(5,6)
    fmt.Println(q)
}

这样话咱们就能够只获取其中一个值即可。

其实 GO 语言函数式编程编程的语言,函数是十分重要的,所以咱们再高端一点的函数的写法是能够将函数自身作为一个参数传入函数的,说的比拟绕,其实自身开始去承受的时候也是有点难了解,老猫在此先把例子写一下,大家试着去了解一下,当然前面的话老猫会有更具体地对函数式编程的介绍,具体的例子如下

func apply(op func(int,int) int,a,b int) int{
    fmt.Printf("Calling %s with %d,%d\n",
        runtime.FuncForPC(reflect.ValueOf(op).Pointer()).Name(),a,b)
    return op(a,b)
}

咱们对 GO 语言的函数来做一个简略的总结:

  • 返回值类型写在前面
  • 能够返回多个值
  • 函数能够作为参数
  • 没有默认参数,可变参数,重载等等

指针

相干定义

关注老猫的应该大多数是软件业余的同学,不知道大家有没有相熟过 C 语言,C 语言中其实也有指针,C 语言的指针绝对还是比拟难的。其实 GO 语言也有指针,相对而言比较简单,因为 GO 语言的指针不能运算。

指针说白了就是一个指针指向了一个值的内存地址。

GO 语言中的去地址符为 &,放到变量以前的话就会返回相应的变量内存地址。看个例子如下:

package main

import "fmt"
func main() {
   var a int = 10  
   fmt.Printf("变量的地址: %x\n", &a)
}

这个呢,其实就是 GO 语言的地址获取形式,那咱们如何去拜访它呢?那么咱们的指针就退场了,如下代码示例

var var_name *var-type

var-type 为指针类型,var_name 为指针变量名称,* 用于指定变量是作为一个指针。那么咱们再来看上面的例子:

var ip *int        /* 指向整型 */
var fp *float32    /* 指向浮点型 */

那么以上其实就是定义了两个指针,别离指向 int 以及 float32。

应用指针

package main

import "fmt"

func main() {
   var a int= 20   /* 申明理论变量 */
   var ip *int        /* 申明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &a)

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量贮存的指针地址: %x\n", ip)

   /* 应用指针拜访值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip)
}

那么咱们失去的后果为

a 变量的地址是: 20818a220
ip 变量贮存的指针地址: 20818a220
*ip 变量的值: 20

GO 语言其实也会存在空指针,当一个指针被定义后没有调配到任何变量时,它的值为 nil。nil 指针也称为空指针。nil 在概念上和其它语言的 null、None、nil、NULL 一样,都指代零值或空值。一个指针变量通常缩写为 ptr。

如下例子

package main

import "fmt"

func main() {
   var  ptr *int
   fmt.Printf("ptr 的值为 : %x\n", ptr)
}

后果

ptr 的值为 : 0

那么咱们个别对空指针的判断即为

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

以上就是老猫带大家入一下指针的门,当然也是老猫的入门。后续,咱们会在理论的例子中来缓缓领会指针的用法。

值传递以及援用传递

那么什么是值传递,什么是援用传递?咱们简略地来看一段 C ++ 的代码,具体如下:

void pass_by_val(int a) {a++;}
void pass_by_ref(int &a){a++;}
int main(){
   int a = 3;
   pass_by_val(a);
   printf("After pass_by_val:%d\n",a);
   pass_by_ref(a);
   printf("After pass_by_ref:%d\n",a);
}

下面两个办法,其中一个是值传递一个是援用传递,那么最终输入的后果是多少呢?大家能够先思考一下。其实答案为下面是 3 上面是 4,那么为什么呢?

咱们来看第一种,第一种的话是值传递,值传递的形式其实在下面的例子中能够这么了解,该函数是将 main 中的值拷贝一份放到了函数中,尽管在函数中加了 1,然而外层原始的那个值还是 3,所以最终输入的也还是 3。

咱们再来看另外一种,援用传递,从入参来看的话,其实外面的 a 以及里面的 a 所援用的都是同一个地址,所以当外部函数对 a 进行自增的时候,里面的函数 a 的值就产生了变动,变成了 4。

那么咱们的 GO 是值传递还是援用传递,其实 GO 语言只有值传递。

大家可能有点懵了,其实很多时候,大家不必太过纠结,因为在理论的用法中咱们往往通过函数 return 的值就能解决相干问题。

写在最初

下面呢,其实老猫和大家分享了 GO 语言的函数定义,以及一个比拟重要的指针的概念,在前面的学习中,咱们来更加深刻地去领会。在实践中去缓缓加深印象。当然下面的例子也心愿大家可能照着写一下,运行着领会一下。有不了解的欢送大家一块沟通一起提高。
我是老猫,更多内容,欢送大家搜寻关注老猫的公众号“程序员老猫”。

退出移动版