回顾一下上一篇博客,主要是和大家分享了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语言的函数定义,以及一个比较重要的指针的概念,在后面的学习中,我们来更加深入地去体会。在实践中去慢慢加深印象。当然上面的例子也希望大家能够照着写一下,运行着体会一下。有不理解的欢迎大家一块沟通一起进步。

我是老猫,更多内容,欢迎大家搜索关注老猫的公众号“程序员老猫”。

跟着老猫来搞GO,基础进阶的更多相关文章

  1. 跟着老猫来搞GO,集跬步而致千里

    上次博客中,老猫已经和大家同步了如何搭建相关的GO语言的开发环境,相信在车上的小伙伴应该都已经搞定了环境了.那么本篇开始,我们就来熟悉GO语言的基础语法.本篇搞定之后,其实期待大家可以和老猫一样,能够 ...

  2. 跟着老猫来搞GO-容器(1)

    前期回顾 前面的一章主要和大家分享了GO语言的函数的定义,以及GO语言中的指针的简单用法,那么本章,老猫就和大家一起来学习一下GO语言中的容器. 数组 数组的定义 说到容器,大家有编程经验的肯定第一个 ...

  3. 跟着老猫来搞GO,"面向对象"

    前言 之前和大家分享了容器以及相关的基础语法,以及函数,相信如果大家有接触过C++或者java的朋友都晓得面向对象,其实在GO语言中也存在面向对象,但是还是比较简单的,下面我们来看一下GO语言的&qu ...

  4. 跟着老猫来搞GO-内建容器Map

    前期回顾 在上面的文章中,老猫和大家分享了GO语言中比较重要的两种数据结构,一种是数组,另外一种是基于数组的slice.本篇文章想要继续和大家分享剩下的容器以及字符字符串的处理. MAP map的定义 ...

  5. 跟着老猫一起来学GO,环境搭建

    老猫的GO学习系列博客已经正式发车了,相信大家以前学习一门编程语言的时候也有经验,咱们一般都是从环境开始,在此呢,大家也跟着老猫从最开始的搭建环境开始. GO语言的安装 首先呢,我们开始需要下载GO语 ...

  6. 老王Python培训视频教程(价值500元)【基础进阶项目篇 – 完整版】

    老王Python培训视频教程(价值500元)[基础进阶项目篇 – 完整版] 教学大纲python基础篇1-25课时1.虚拟机安装ubuntu开发环境,第一个程序:hello python! (配置开发 ...

  7. 我用Axure制作了一款火影小游戏 | PM老猫

    Axure不仅仅是一个原型工具,除了原型之外还可以用来制作一些静态网页,这点对于不懂代码或前端的同学来说挺实用.之前整理了一版<Axure函数自查表>,因为感觉内容太多又对前端样式及脚本感 ...

  8. 前端基础进阶(五):全方位解读this

    https://segmentfault.com/a/1190000012646488  https://yangbo5207.github.io/wutongluo/ 说明:此处只是记录阅读前端基础 ...

  9. 【简单易懂的AMV图文教程-2】VEGAS基础进阶——认识关键帧

    [简单易懂的AMV图文教程-2]VEGAS基础进阶--认识关键帧 经过了上一期VEGAS基础教程的学习,相信大家都能独立完成一些比较简单的纯剪辑作品了.今天在这里为大家继续介绍VEGAS的一大基础应用 ...

随机推荐

  1. find_elements与find_element的区别

    find_element不能使用len,find_elements可以使用len获取元素数量,判断页面有无某个元素,这个方法可以用来断言. 如添加用户后,判断是否添加成功. 删除用户后,判断是否删除成 ...

  2. 关于Redis的十个高频面试问题

    文件来自大神的分析,小弟引用.希望更多的资源能被更多的人分享到!!! 一.Redis有哪些数据结构? 字符串String.字典Hash.列表List.集合Set.有序集合SortedSet. 如果你是 ...

  3. C# 在PPT中添加数学公式

    本次内容介绍在C#程序中给PPT幻灯片添加Latex数学公式,添加公式前,首先需要在幻灯片中插入一个Shape形状,在形状的段落中通过方法Paragraphs.AddParagraphFromLate ...

  4. Sentry 监控 - Snuba 数据中台架构(Query Processing 简介)

    系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...

  5. 初步认识HCIA,什么是计算机网络,拓扑,网络的发展,交换机,路由器,IP,光纤,带宽,广播,ARP......

    HCIA ---- 华为认证初级网络工程师 云技术 --- 云存储 云计算 计算机技术 : ​ --- 抽象语言 -- 电线号的转换 抽象语言 -- 编码 ---- 应用层 编码 --- 二进制 -- ...

  6. CF739E Gosha is hunting(费用流/凸优化dp)

    纪念合格考爆炸. 其实这个题之前就写过博客了,qwq但是不小心弄丢了,所以今天来补一下. 首先,一看到球的个数的限制,不难相当用网络流的流量来限制每个球使用的数量. 由于涉及到最大化期望,所以要使用最 ...

  7. pycharm设置文件中显示模板内容

    pycharm中设置自己的文件模板  File>>Settings>>Editor>>File and Code Templates 选择文件类型或者输入文件类型 ...

  8. 如何在印刷品中使用遵循SIL Open Font License协议的字体

    如何在印刷品中使用遵循SIL Open Font License协议的字体 昨天在知乎看到了一个问题,( 如何在设计中声明字体开源许可证? - 知乎 (zhihu.com),恰好最近在研究一些开源协议 ...

  9. 全场景效能平台猪齿鱼常用的前端css实现方案

    ​ 居中 最常用的height + line-height,以及margin:0 auto的居中方式就不再阐述,以下介绍两种容错性高的实现方案. flex布局实现 ​ 猪齿鱼前端日常开发中,我们多以f ...

  10. 【UE4 设计模式】命令模式 Command Pattern

    概述 描述 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化:对请求排队或者记录请求日志,以及支持可撤销的操作. 命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务 ...