go语言学习——2.x

news2024/11/16 7:21:02

文章目录

  • 控制结构
    • if-else
    • switch
    • for(range)
      • break和continue
      • 标签与goto
  • 函数
    • 参数与返回值
      • 传递变长参数
      • defer
      • 内置函数
      • 递归函数
      • 函数作为参数
      • 闭包
      • 计算函数的执行时间

控制结构

if-else

if condition{
	//do something
}
if condition{
	//do something
}else{
	//do something
}
if condition1{
	//do something
}else if condition2{
	//do something
}else{
	//cathc-all or default
}
//else-if分支没有数量限制,但为了代码的可读性,不要在if后面加入太多的else-if结构。
//当if结构中有break、continue、goto或return语句时,常省略else部分
if condition{
	return x
}
return y
//不要同时在if-else结构的两个分支里都使用return语句,这会导致编译错误
//判断go程序的操作系统类型
if runtime.GOOS == "windows"{
	...
}else{//unix-like
	...
}

if可以包含一个初始化语句,比如给一个变量赋值,具体格式如下:

if initialization; condition{
	// do something
}
val:=10
if val>max{
	//...
}
//可以写成
//使用:=声明的变量作用域只存在于if结构中
if val:=10; val>max{
	//...
}


if value:=process(data); value>max{
	...
}

strconv.Atoi可以将一个字符串转换为一个整数

anInt, _ = strconv.Atoi(origStr)

如果不能被转换为整数,anInt的值会变成0,而_忽视了错误,程序会继续运行,正确的做法是检查错误

package main

import (
	"fmt"
	"strconv"
)

func main(){
	var orig string="ABC"
	var newS string
	
	fmt.Printf("The size of ints is: %d\n",strconv.IntSize)
	
	an,err:=strconv.Atoi(orig)
	if err!=nil{
		fmt.Printf("orig %s is not an integer - exiting with error\n",orig)
		return
	}
	fmt.Printf("The integer is %d\n",an)
	an=an+5
	newS=strconv.Itoa(an)
	fmt.Printf("The new string is :%s\n",newS)
}
//习惯用法
value,err:=pack1.function1(param1)
if err!=nil{
	fmt.Printf("An error occured in pack1.function1 with parameter %v", param1)
	return err
}

//如果想在错误发生的同时终止程序运行,可以使用os包的Exit函数:
if err!=nil{
	fmt.Printf("Program stopping with err %v",err)
	os.Exit(1)
}
//推出代码1可以使用外部脚本获取到

switch

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
  • 每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
  • 一旦成功地匹配到某个分支,在执行完相应代码后就会退出整个 switch 代码块,不需要特别使用 break 语句来表示结束。
  • 程序也不会自动地去执行下一个分支的代码。如果在执行完每个分支的代码后,还希望继续执行后续分支的代码,可以使用 fallthrough 关键字来达到目的。
switch i {
    case 0: // 空分支,只有当 i == 0 时才会进入分支
    case 1:
        f() // 当 i == 0 时函数不会被调用
}

switch i {
    case 0: fallthrough
    case 1:
        f() // 当 i == 0 时函数也会被调用
}
switch {
    case condition1:
        ...
    case condition2:
        ...
    default:
        ...
}
switch initialization {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

//示例
switch result := calculate(); {
    case result < 0:
        ...
    case result > 0:
        ...
    default:
        // 0
}

switch a, b := x[i], y[j]; {
    case a < b: t = -1
    case a == b: t = 0
    case a > b: t = 1
}

另外还有, select结构,用于channel选择,后续会提到

for(range)

for 初始化语句; 条件语句; 修饰语句 {}
package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Printf("This is the %d iteration\n", i)
    }
}

同时使用多个计数器

for i, j := 0, N; i < j; i, j = i+1, j-1 {}

break和continue

一个 break 的作用范围为该语句出现后的最内部的结构,它可以被用于任何形式的 for 循环(计数器、条件判断等)。但在 switch 或 select 语句中,break 语句的作用结果是跳过整个代码块,执行后续的代码。

关键字 continue 忽略剩余的循环体而直接进入下一次循环的过程,但不是无条件执行下一次循环,执行之前依旧需要满足循环的判断条件。

标签与goto

for、switch 或 select 语句都可以配合标签(label)形式的标识符使用,即某一行第一个以冒号(:)结尾的单词

package main

import "fmt"

func main() {

LABEL1:
    for i := 0; i <= 5; i++ {
        for j := 0; j <= 5; j++ {
            if j == 4 {
                continue LABEL1
            }
            fmt.Printf("i is: %d, and j is: %d\n", i, j)
        }
    }

}
package main

func main() {
    i:=0
    HERE:
        print(i)
        i++
        if i==5 {
            return
        }
        goto HERE
}

函数

三种类型的函数:

  • 普通的带名字的函数
  • 匿名函数或者lambda函数
  • 方法(Method)

除了main()、init()函数外,其他所有类型的函数都可以有参数与返回值。函数参数、返回值以及它们的类型被统称为函数签名。

package main

func main(){
	greeting()
}

func greeting(){
	println("In greeting: Hi!!!")
}

参数与返回值

接收参数,返回零个或多个值

通过return关键字返回一组值。

有返回值的函数都必须以return或panic结尾

return之后的语句都不会被执行

函数定义时,形参一般是有名字的,也可以定义没有形参名的函数,只有相应的形参类型:func f(int, int, float64)

没有参数的函数通常被称为niladic函数,就像mian.main()

按值传递call by value、按引用传递call by reference

go默认使用值传递来传递参数,也就是传递参数的副本。对传递的值进行修改,不会影响原来的变量。Function(arg1)

如果希望函数可以直接修改参数的值,而不是对副本进行操作,需要将参数的地址传递给函数(变量名前加&符号),这就是按引用传递。Function(&arg1)。此时传递给函数的是一个指针,指针的值(一个地址)会被复制,但指针的值所指向的地址上的值不会被复制;通过这个指针的值来修改这个值所指向的地址上的值。

传递指针的消耗比传递副本来的少。

在函数调用时,切片、字典、接口、通道这样的引用类型都默认使用引用传递(即使没有显式的指出指针)

package main

import "fmt"

func main() {
    fmt.Printf("Multiply 2 * 5 * 6 = %d\n", MultiPly3Nums(2, 5, 6))
    // var i1 int = MultiPly3Nums(2, 5, 6)
    // fmt.Printf("MultiPly 2 * 5 * 6 = %d\n", i1)
}

func MultiPly3Nums(a int, b int, c int) int {
    // var product int = a * b * c
    // return product
    return a * b * c
}
//Multiply 2 * 5 * 6 = 60

命名的返回值
当需要返回多个非命名返回值时,需要使用 () 把它们括起来,比如 (int, int)

命名返回值作为结果形参(result parameters)被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的 return 语句。需要注意的是,即使只有一个命名返回值,也需要使用 () 括起来

package main

import "fmt"

var num int = 10
var numx2, numx3 int

func main() {
    numx2, numx3 = getX2AndX3(num)
    PrintValues()
    numx2, numx3 = getX2AndX3_2(num)
    PrintValues()
}

func PrintValues() {
    fmt.Printf("num = %d, 2x num = %d, 3x num = %d\n", num, numx2, numx3)
}

func getX2AndX3(input int) (int, int) {
    return 2 * input, 3 * input
}

func getX2AndX3_2(input int) (x2 int, x3 int) {
    x2 = 2 * input
    x3 = 3 * input
    // return x2, x3
    return
}

空白符

package main

import "fmt"

func main() {
    var i1 int
    var f1 float32
    i1, _, f1 = ThreeValues()
    fmt.Printf("The int: %d, the float: %f \n", i1, f1)
}

func ThreeValues() (int, int, float32) {
    return 5, 6, 7.5
}

改变外部变量

传递指针,赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用return返回

package main

import (
    "fmt"
)

// this function changes reply:
func Multiply(a, b int, reply *int) {
    *reply = a * b
}

func main() {
    n := 0
    reply := &n
    Multiply(10, 5, reply)
    fmt.Println("Multiply:", *reply) // Multiply: 50
}

传递变长参数

如果函数的最后一个参数是采用...type的形式,函数就可以处理一个变长的参数,这个长度可以为0,这样的函数称为变长函数。

func myFunc(a,b,arg ....int){}
func Greeting(prefix string, who ...string)
Greeting("hello:","joe","anna","eileen")

如果参数被存储在一个slice类型的变量中,可以通过slice… 的形式来传递参数调用变参函数

package main

import "fmt"

func main() {
    x := min(1, 3, 2, 0)
    fmt.Printf("The minimum is: %d\n", x)
    slice := []int{7,9,3,5,1}
    x = min(slice...)
    fmt.Printf("The minimum in the slice is: %d", x)
}

func min(s ...int) int {
    if len(s)==0 {
        return 0
    }
    min := s[0]
    for _, v := range s {
        if v < min {
            min = v
        }
    }
    return min
}
//The minimum is: 0
//The minimum in the slice is: 1

defer

关键字defer允许推迟到函数返回之前(或者任意位置执行return语句之后)一刻才执行某个语句或函数
defer和return的执行顺序是先返回值赋值,然后执行defer,然后return到函数调用处

package main
import "fmt"

func main() {
    function1()
}

func function1() {
    fmt.Printf("In function1 at the top\n")
    defer function2()
    fmt.Printf("In function1 at the bottom!\n")
}

func function2() {
    fmt.Printf("function2: Deferred until the end of the calling function!")
}
//In Function1 at the top
//In Function1 at the bottom!
//Function2: Deferred until the end of the calling function!
func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}
//打印0

有多个defer行为被注册时,会以逆序执行

func f() {
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d ", i)
    }
}
// 4 3 2 1 0

defer允许进行一些函数执行完成后的收尾工作:
1、关闭文件流

defer file.Close()

2、解锁加密资源

mu.Lock()
defer mu.Unlock()

3、打印最终报告

printHeader()
defer printFooter()

4、关闭数据库连接

defer disconnectFromDB()

使用defer语句实现代码追踪

package main

import "fmt"

func trace(s string)   { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }

func a() {
    trace("a")
    defer untrace("a")
    fmt.Println("in a")
}

func b() {
    trace("b")
    defer untrace("b")
    fmt.Println("in b")
    a()
}

func main() {
    b()
}
//entering: b
//in b
//entering: a
//in a
//leaving: a
//leaving: b
package main

import "fmt"

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}

func a() {
    defer un(trace("a"))
    fmt.Println("in a")
}

func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}

func main() {
    b()
}

内置函数

在这里插入图片描述

递归函数

package main

import "fmt"

func main() {
    result := 0
    for i := 0; i <= 10; i++ {
        result = fibonacci(i)
        fmt.Printf("fibonacci(%d) is: %d\n", i, result)
    }
}

func fibonacci(n int) (res int) {
    if n <= 1 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}

函数作为参数

函数可以作为其他函数进行传递,然后在其他函数内调用,一般称之为回调。

package main

import (
    "fmt"
)

func main() {
    callback(1, Add)
}

func Add(a, b int) {
    fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}

func callback(y int, f func(int, int)) {
    f(y, 2) // this becomes Add(1, 2)
}
//The sum of 1 and 2 is: 3

闭包

当不希望给函数起名字的时候,可以使用匿名函数,func(x, y int) int{ return x+y }

这样的函数不能独立存在,但可以被赋予某个变量,即保存函数的地址到变量中:fplus:=func(x,y int) int {return x+y},然后通过变量名对函数进行调用:fplus(3,4)

也可以直接对匿名函数进行调用:func(x,y int) int {return x+y}(3,4)

func() {
    sum := 0
    for i := 1; i <= 1e6; i++ {
        sum += i
    }
}()
//花括号 {} 涵盖着函数体,最后的一对括号表示对该匿名函数的调用。

defer语句和匿名函数

关键字defer经常配合匿名函数使用,可以用于改变函数的命名返回值。

匿名函数同样被称之为闭包,允许调用定义在其他环境中的变量。

函数作为返回值

package main

import "fmt"

func main() {
    // make an Add2 function, give it a name p2, and call it:
    p2 := Add2()
    fmt.Printf("Call Add2 for 3 gives: %v\n", p2(3))
    // make a special Adder function, a gets value 2:
    TwoAdder := Adder(2)
    fmt.Printf("The result is: %v\n", TwoAdder(3))
}

func Add2() func(b int) int {
    return func(b int) int {
        return b + 2
    }
}

func Adder(a int) func(b int) int {
    return func(b int) int {
        return a + b
    }
}
//Call Add2 for 3 gives: 5
//The result is: 5
package main

import "fmt"

func main() {
    var f = Adder()
    fmt.Print(f(1), " - ")
    fmt.Print(f(20), " - ")
    fmt.Print(f(300))
}

func Adder() func(int) int {
    var x int
    return func(delta int) int {
        x += delta
        return x
    }
}
//1 - 21 - 321

在多次调用中,变量 x 的值是被保留的,即 0 + 1 = 1,然后 1 + 20 = 21,最后 21 + 300 = 321:闭包函数保存并积累其中的变量的值,不管外部函数退出与否,它都能够继续操作外部函数中的局部变量。

计算函数的执行时间

time包的Now()和Sub函数

start := time.Now()
longCalculation()
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/593265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringMVC03:Restfule和控制器

目录 一、控制器Controller 二、实现controller接口 三、使用注解Controller 四、RequestMappinng 五、RestFul风格 六、学习测试 1.再新建一个类RestfulController 2.在SPring MVC种可以使用PathVariable注解&#xff0c;让方法参数的值对应绑定到一个URI模板变量上。…

【hello C++】类和对象(中)

目录 1. 类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3. 析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 5.3 前置和后置重载 7.const成员 8.取地址及const取地址操作符重载 类和对象&#x1f337…

《Java并发编程实战》课程笔记(六)

管程&#xff1a;并发编程的万能钥匙 什么是管程 Java 采用的是管程技术&#xff0c;synchronized 关键字及 wait()、notify()、notifyAll() 这三个方法都是管程的组成部分。 管程和信号量是等价的&#xff0c;所谓等价指的是用管程能够实现信号量&#xff0c;也能用信号量实…

通用AppKey签名验证软件

一、 需求说明 签名验证是一种技术&#xff0c;用于确保数据完整性和身份验证。在Java应用程序中&#xff0c;签名通常是由开发人员提供的一个字符串&#xff0c;它基于请求的内容和一些密钥信息生成。这个签名可以被认为是一种指纹&#xff0c;它唯一地标识了请求的内容&…

BLECommonTool通用测试工具介绍

工具下载地址&#xff1a;BLECommonTool通用工具资源-CSDN文库 大家在使用过程中&#xff0c;如有发现bug或有更好的建议&#xff0c;欢迎留言或发我QQ邮箱&#xff1a;1255033066qq.com. 工具界面 以下是关于GMBLETool工具的详细使用说明&#xff1a; 蓝牙适配器状态检测&…

springcloudAlibaba整合knife4j整合swagger整合gateway,并且同步到Yapi上

springcloudAlibaba整合knife4j整合swagger整合gateway&#xff0c;并且同步到Yapi上 1.gateway模块 1.pom引入 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version&g…

什么是七专,电子元器件分级详细总结

🏡《电子元器件高级指南》 目录 0,概述1,商业级元器件2,工业级元器件3,汽车工业级元器件4,七专级元器件5,军级元器件6,航天级元器件0,概述 随着科学技术的发展,以及集成电路技术的不断进步。电子元器件的应用越来越广泛。在不同的应用场景下,往往需要不同等级的电子…

(双指针 ) 15. 三数之和 ——【Leetcode每日一题】

❓15. 三数之和 难度&#xff1a;中等 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a…

pip安装python库速度慢、失败及超时报错解决办法

背景&#xff1a; 随着人工智能的不断兴起&#xff0c;python作为最接近人工智能的语言&#xff0c;变得越来越流行&#xff0c;人生苦短&#xff0c;python要学起来。之所以越来用的人喜欢学习python和研究Python&#xff0c;除了python本身便于学些、语法简短、面向对象等特点…

静态库与动态库的区别

静态库与动态库的区别 静态库动态库 首先用OpenCV的开源库来举个例子了解一下库文件的分类&#xff1a; bin文件夹里面放的都是dll文件&#xff1b; lib文件夹里面放的都是伴随dll文件的动态lib文件&#xff1b; staticlib文件夹里面放的才是真正的静态lib文件&#xff0c;和…

专利费减备案操作流程——让你申请专利时的官费大大打折

【系列专栏】&#xff1a;博主结合工作实践输出的&#xff0c;解决实际问题的专栏&#xff0c;朋友们看过来&#xff01; 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实…

【为什么控件的引用和控件的代理要用weak Objective-C语言】

一、还记得我们给大家说过,UI控件,当用一个属性,引用UI控件的时候,那个标记要用weak, 1.为什么,但是用strong,是不是也行, 但是,如果是控件的代理对象,是不是一定得用weak, 我现在就告诉你,为什么, 注意听,现在,比如说,这个是控制器, 我先解释,为什么UI控…

Java实战-基于JDK的LRU算法实现、优雅的实现代码耗时统计(Spring AOP、AutoCloseable方式)

场景 Java中基于JDK的LRU算法实现 LRU算法-缓存淘汰算法-Least recently used,最近最少使用算法 根据数据的历史访问记录来进行淘汰数据&#xff0c;其核心思想是&#xff1a;如果有数据最近被访问过&#xff0c;那么将来被访问的几率也更高 在Java中可以利用LinkedHashMap…

34. Linux系统下打包qt应用程序

1. 说明 对程序进行打包前需要在Release模式对程序代码进行编译,然后得到编译后的可执行文件,正常情况下这个可执行文件是可以双击打开运行的,如果无法双击运行,可在**.pro**文件内加入下面的代码: QMAKE_LFLAGS += -no-pie TEMPLATE = app同时将main.qml文件中的Window…

【总结】对接达梦数据库DM8详细教程

目录 1.达梦数据库-技术文档2.软件安装包下载2.1 iso 安装版2.2 docker 安装版 3.DM8单机安装部署规范4.安装操作步骤4.1 安装docker4.2 docker安装dameng&#xff08;推荐&#xff09; 5. 启动/停止数据库6.客户端连接使用7.DDL SQL实践7.1 创建表空间7.2 建表语句 8.DML SQL实…

「2023大学生就业报告 」出炉,应届生都去了哪些行业?

2023年的应届毕业生人数再创新高&#xff0c;达到1158万人&#xff0c;是不是开始担忧他们的就业了&#xff1f;别急&#xff0c;最近Boss直聘发布的一组数据&#xff0c;会让这样的担忧有所缓解。 期望薪资有所下降 和增长明显的毕业人数相反的是&#xff0c;这一届大专、本…

网络流量监控及流量异常检测

当今的企业面临着许多挑战&#xff0c;尤其是在监控其网络基础设施方面&#xff0c;需要确保随着网络规模和复杂性的增长&#xff0c;能够全面了解网络的运行状况和安全性。为了消除对网络性能的任何压力&#xff0c;组织应该采取的一项重要行动是使用随组织一起扩展的工具监控…

探究工业设备状态监测的典型对象和常用方法

工业设备状态监测的目的是实时掌握设备的健康状况&#xff0c;及时发现潜在故障迹象&#xff0c;并采取相应的维修和维护措施。通过有效的状态监测&#xff0c;企业可以降低设备故障风险&#xff0c;减少计划外停机时间&#xff0c;提高生产效率&#xff0c;节约维护成本&#…

深兰科技亮相2023数博会:硅基知识大模型推动个人数字化产业

近日&#xff0c;2023中国国际大数据产业博览会 “数字经济与实体经济深度融合”论坛在贵阳举行。腾讯云、京东集团、网易、深兰科技等8家企业负责人进行了行业演讲。 作为2023数博会的专业论坛之一&#xff0c;本次论坛以“数融百业 创变赋新”为主题&#xff0c;从数实融合视…

项目冲突管理机制的4大关键环节

1、冲突预防功能 预先采取一些措施防止冲突的产生&#xff0c;如建立有效的沟通机制。在项目开始前&#xff0c;制定沟通计划、沟通频率和方式&#xff0c;以确保项目成员充分了解自我职责和任务&#xff0c;并自愿分享和讨论。通过有效的沟通机制&#xff0c;最大限度避免不必…