Golang

函数参数传递方式

  1. 基本介绍
    函数传递方式有两类:值类型和引用类型。值类型参数默认就是值传递,引用类型参数默认为引用传递。
  2. 两种传递方式
    1)值传递
    2)引用传递
    实际上不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递是值的拷贝,引用传递的是地址的拷贝。一般情况下,地址拷贝效率高,因为其数据量小,而值拷贝取决于拷贝的数据大小,数据越大,效率越低。
  3. 值类型和引用类型
    1)值类型:基本数据类型(int float系列,bool string complex64/128等),数组和结构体
    2)引用类型:指针,slice切片,map,管道chan,interface

变量作用域

  1. 函数内部声明/定义的变量叫局部变量(不论变量首字母是否大写),作用域仅限于函数内部
  2. 函数外部声明/定义的变量叫全局变量,作用域整个包都有效,如果变量名首字母大写,则作用域整个程序都有效
  3. 如果变量一个代码块中,比如for/if中,那么这个变量的作用域就在该代码块中。(与其他语言的一大区别)

全局变量使用细节
4. 当在函数内定义了一个与已存在的全局变量相同名字的变量时,在该函数内,编译器遵循就近原则

package main

import "fmt"

var name = "tom" // 全局变量

func test01() {
	fmt.Println(name)
}
func test02() {
	name := "jack" //1 编译器采用就近原则
	//name = jack  // 2
	fmt.Println(name)
}

func main() {
	fmt.Println(name) //tom    2 tom
	test01()          //tom     2 tom
	test02()          //jack      2 jack
	test01()          //tom        2 jack
	//全局变量可以在代码块中直接改变值,但局部变量要在代码块中改变的值影响到自身需要使用引用变量

}
  1. 全局变量不能使用类型推导形式。例如:Age:=20//实际上包含了申明/定义语句 var Age int 和赋值语句Age = 20 。在函数体外可以声明/定义、初始化变量,但不能进行语句操作(赋值语句)
package main

import "fmt"

var Name = "tom" // 全局变量
Age := 20  //报错
func main() {
	fmt.Println(Name) 
}

字符串常用的系统函数

  1. 统计字符串的长度,按字节len(str)
    golang的编码统一编码为utf-8,ASCII的字符(字母和数字)占一个字节汉子占3个字节。
  2. 当含义中文的字符串遍历时,需先对字符串转为rune切片,防止乱码现象。(str1 := []rune(str) )
  3. 字符串转其他类型,其他类型转字符串。使用strconv包,func Parse…方法:字符串转其他类型;func Format…方法:其他类型转字符串。基本类型转string推荐使用fmt.Sprintf()方法。
package main

import (
	"fmt"
	"strconv"
	// _ "unsafe" //如果我们没有使用一个包,但是又不想去掉,前面加入_表示忽略此包
)

//演示golang中基本数据类型转换成string使用
// 使用到函数:fmt.Sprintf()
func main() {
	var num1 int = 99
	var num2 float64 = 23.456
	var b bool = true
	var myChar byte = 'h'
	var str string //空的str

	//使用第一种方式转换来转换 fmt.Sprintf(format string, a...interface{})
	//根据format参数生成格式化的字符串并返回该字符串。
	str = fmt.Sprintf("%d", num1)
	fmt.Printf("str type %T, str=%v,%s\n", str, str, str)
	fmt.Println(str)

	str = fmt.Sprintf("%f", num2)
	fmt.Printf("str type %T, str=%v,%s\n", str, str, str)

	str = fmt.Sprintf("%t", b)
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

	str = fmt.Sprintf("%c", myChar)
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

	//第二种方式 strconv包中函数
	var num3 int = 99
	var num4 float64 = 23456.154852
	var b2 bool = true
	var num5 int64 = 4562

	str = strconv.FormatInt(int64(num3), 10) //10:十进制 还可是 2 8 16
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

	//strconv.FormatFloat(num4, 'f', 6, 64)
	//'f'转换成的格式, 6:精度, 64:来源num4的格式
	str = strconv.FormatFloat(num4, 'e', 6, 64) // e:科学计数法
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

	str = strconv.FormatBool(b2)
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

	//strconv.Itoa():strconv包中的,将int类转换为string类
	str = strconv.Itoa(int(num5))
	fmt.Printf("str type %T, str=%v,%q\n", str, str, str)

  1. 字符串转[]byte: var bytes = []byte("hello go),为了将字符串写入二进制文件,使用byte切片[]byte(string)。
  2. []byte转字符串 str := string([]byte(97,98,99) ,输出str结果为对应的ASCII码值“abc”
  3. 查找子字符串是否在指定的字符串中,使用strings包中的Contains方法。

func Contains(s, substr string) bool
Example
fmt.Println(strings.Contains(“seafood”, “foo”))
fmt.Println(strings.Contains(“seafood”, “bar”))
fmt.Println(strings.Contains(“seafood”, “”))
fmt.Println(strings.Contains("", “”))
Output:
true
false
true
true

  1. 查找一个字符串有几个指定的子字符串。strings包中func Count(s, sep string) int,返回字符串有几个不重复的sep字符串。

Example
fmt.Println(strings.Count(“cheese”, “e”))
fmt.Println(strings.Count(“five”, “”)) // before & after each rune
Output:
3
5

  1. 字符串的比较,若不区分字母大小写则使用==,需要区分大小写,则使用strings包中的func EqualFold(s, t string) bool(判断两个utf-8编码字符串(将unicode大写、小写、标题三种格式字符视为相同)是否相同)
fmt.Println("结果", "abc" == "ABC")            //结果 flase
	fmt.Println(strings.EqualFold("abc", "ABC")) //true
  1. 返回子串在字符串第一次出现时的index值,如果没有则返回-1:strings.Index(s,t string)
fmt.Println(strings.Index("NLT_abcabcabc", "abc")) //4
fmt.Println(strings.Index("NLT_abcabcabc", "hi")) //-1
  1. 返回子串在字符串最后一次出现时的index值,如果没有则返回-1:strings.LastIndex(s,t string)
  2. 将指定的子串替换成另外一个子串:strings包func Replace(s, old, new string, n int) string(返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串。)

Example
fmt.Println(strings.Replace(“oink oink oink”, “k”, “ky”, 2))
fmt.Println(strings.Replace(“oink oink oink”, “oink”, “moo”, -1))
Output:
oinky oinky oink
moo moo moo

注意:s并不会被影响,替换后是得到一个新的字符串

str2 := "go go hello"
	fmt.Println(strings.Replace(str2, "go", "golang", 1)) //不会影响str2的值,替换后得到一个新字符串
	fmt.Println(strings.Replace("go go hello", "go", "golang", -1))
	fmt.Println(str2) //go go hello

11.按照指定的某个字符,为分隔标识,将一个字符串拆分成字符串数组。strings.Split(s, sep string) []string。
用去掉s中出现的sep的方式进行分割,会分割到结尾,并返回生成的所有片段组成的切片(每一个sep都会进行一次切割,即使两个sep相邻,也会进行两次切割)。如果sep为空字符,Split会将s切分成每一个unicode码值一个字符串。

Example
fmt.Printf("%q\n", strings.Split(“a,b,c”, “,”))
fmt.Printf("%q\n", strings.Split(“a man a plan a canal panama”, “a “))
fmt.Printf(”%q\n”, strings.Split(" xyz “, “”))
fmt.Printf(”%q\n", strings.Split("", “Bernardo O’Higgins”))
Output:
[“a” “b” “c”]
["" “man " “plan " “canal panama”]
[” " “x” “y” “z” " “]
[””]

  1. 将字符串的字母大小写转换:strings.ToLower(s)/strings.ToUpper(s)
  2. 将字符串左右两边的空格去掉。使用strings.TrimSpace(s string) string。返回将s前后端所有空白(unicode.IsSpace指定)都去掉的字符串。

Example
fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
Output:
a lone gopher

  1. 将字符串两边指定的字符去掉。使用strings.Trim(s string, cutset string) string。返回将s前后端所有cutset包含的utf-8码值都去掉的字符串。

Example
fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))//把左右两边的!和空格去掉
Output:
[“Achtung! Achtung”]

  1. 将字符串前段指定字符去掉:strings.TrimLeft(s string, cutset string) string;将字符串后端段指定字符去掉:strings.TrimRight(s string, cutset string) string。
  2. 判断字符串是否以指定的字符串开头:strings.HasPrefix(s, prefix string) bool;判断字符串是否以指定的字符串结尾:strings.HasSuffix(s, suffix string) bool。

时间和日期相关的函数 time包

  1. time.Time类型用于表示时间
  2. 获取当前时间的方法:now:=time.Now()
  3. 获取更详细的日期信息
	//日期和时间相关函数和方法的使用
	//1.获取当前时间
	now := time.Now() // 返回的是time.Time类型
	fmt.Printf("now=%v now type=%T\n", now, now)
	//time.Time 是一种表示时间的类型

	//2.通过now可以获取到年月日,时分秒,使用 func (Time) Year/Month ...等方法
	fmt.Printf("年=%v\n", now.Year())
	fmt.Printf("月=%v\n", now.Month())
	fmt.Printf("日=%v\n", int(now.Day())) // 将November 表示成 11
	fmt.Printf("时=%v\n", now.Hour())
	fmt.Printf("分=%v\n", now.Minute())
	fmt.Printf("秒=%v\n", now.Second())

	fmt.Printf("秒=%v\n", time.Now().Second())
  1. 格式化日期时间:
    1)采用格式化输出
    2)使用func(Time)Format(“2006/01/02 15:04:05”),需注意Format内的标准时间是固定的,不可改动
	//格式化日期时间
	//方式一:格式化输出
	fmt.Printf("当前年月日 %d-%d-%d %d:%d:%d\n", now.Year(), now.Month(), now.Day(),
		now.Hour(), now.Minute(), now.Second())

	//转换为字符串输出
	dateStr := fmt.Sprintf("当前年月日 %d-%d-%d %d:%d:%d\n", now.Year(), now.Month(), now.Day(),
		now.Hour(), now.Minute(), now.Second()) //转换为字符串,但没有输出
	fmt.Printf("dataStr=%s\n", dateStr)

	//方式二采用func (Time) Format方法
	fmt.Println(now.Format("2006/01/02 15:04:05")) //判断时间2006-01-02 15:04:05是固定的
	fmt.Println(now.Format("2006-01-02 "))         //年月日
	fmt.Println(now.Format("15:04:05"))            //时分秒
	fmt.Println(now.Format("15"))                  //输出时
	fmt.Println(now.Format("04"))                  //输出分
	fmt.Println(now.Format("05"))                  //输出秒
}
  1. 时间常量,type Duration int。Duration类型代表两个时间点之间经过的时间,以纳秒为单位。可表示的最长时间段大约为290光年。

const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
常用的时间段。没有定义一天或超过一天的单元,以避免夏时制的时区切换的混乱。
常量的作用:在程序中可以用于获取指定时间单位的时间,比如想得到100毫秒 100 * time.Millisecond

  1. 结合Sleep,使用常量。
	//结合Sleep 使用时间常量/Duration
	//需求:每隔0.1秒打印一个数字,打印到100退出
	for i := 1; i <= 100; i++ {
		fmt.Println(i)
		time.Sleep(time.Millisecond * 100)
  1. 获取当前Unix(秒)时间戳和UnixNano(纳秒)时间戳。(作用:用于获取随机数字)

func (Time) Unix
func (t Time) Unix() int64
Unix将t表示为Unix时间,即从时间点January 1, 1970 UTC到时间点t所经过的时间(单位秒)。

func (Time) UnixNano
func (t Time) UnixNano() int64
UnixNano将t表示为Unix时间,即从时间点January 1, 1970 UTC到时间点t所经过的时间(单位纳秒)。如果纳秒为单位的unix时间超出了int64能表示的范围,结果是未定义的。注意这就意味着Time零值调用UnixNano方法的话,结果是未定义的。

内置函数

Golang设计者为编程方便,提供了一些函数,这些函数可以直接使用,称之为内置函数。在buildin包中。

  1. len:用来求长度,例如string、array、slice、map、channel
  2. new🆕用来分配内存,主要用来分配值类型,比如int、float系列,struct…返回的指针。
//一般的赋值方法
	num1 := 10
	fmt.Printf("num1的类型%T,值为%d,地址为%v\n", num1, num1, &num1)

	//使用new()
	//new:用来分配内存,主要用来分配值类型,比如int、float系列,struct...返回的指针
	num2 := new(int) //类型 *int
	//num2的值为一个指向新的int类型(值为默认值)的空间的地址

	*num2 = 100 //num2指向的值 = 100
	fmt.Printf("num2的类型%T,值(指向的空间地址)为%v,地址为%v,指向的值为%v\n", num2, num2, &num2, *num2)
  1. make:用来分配内存,主要用来分配引用类型,比如channel、map、slice。func make(Type, size IntegerType) Type内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:

切片:size指定了其长度。该切片的容量等于其长度。切片支持第二个整数实参可用来指定不同的容量;
它必须不小于其长度,因此 make([]int, 0, 10) 会分配一个长度为0,容量为10的切片。
映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个
小的起始大小。
通道:通道的缓存根据指定的缓存容量初始化。若 size为零或被省略,该信道即为无缓存的。

错误处理机制

案例:

package main

import "fmt"

func test(){
	n1 := 10
	n2 := 0
	res := n1 / n2
	fmt.Println("res",res) 
}
func main(){
		//测试
		test()
		fmt.Println("main()下面的代码")
}

1)在默认情况下,当发生错误后(panic),程序就会退出(崩溃)
2)如果希望当错误发生后,可以捕获到错误,并进行处理,保证程序可以继续执行。还可以在捕获到错误后,给管理员一个提示(邮件,短信。。。)

错误处理机制基本说明:
1)Go语言为追求简洁,所以GO语言不支持传统的try…catch…finally这种处理
2)Go中引入的处理方式:defer,panic,recover
3)使用场景简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理,使得代码更加健壮。

func recover() interface{}
内建函数recover允许程序管理恐慌过程中的Go程。在defer的函数中,执行recover调用会取回传至panic调用的错误值,恢复正常执行,停止恐慌过程。若recover在defer的函数之外被调用,它将不会停止恐慌过程序列。在此情况下,或当该Go程不在恐慌过程中时,或提供给panic的实参为nil时,recover就会返回nil。

func test() {
	//使用defer + recover 来捕获和处理异常
	defer func() {
		if err := recover(); err != nil { // recover()为内置函数,可以捕获到异常
			fmt.Println(err)
			// 这里可以将错误信息发送给管理员)
			// 伪代码
			fmt.Println("~发送邮件给admin@128.com")
		}
	}() //匿名函数的用法,直接应用 func(int int){}(int int)
	n1 := 10
	n2 := 0
	res := n1 / n2
	fmt.Println("res", res)
}
func main() {
	//测试
	test()
	for i := 1; i <= 15; i++ {
		fmt.Println("main()下面的代码")
		time.Sleep(time.Second)
	}
}

自定义错误
Go程序中,也支持自定义错误,使用errors.New和panic内置函数。
errors.New(“错误说明”),使用字符串创建一个错误,返回一个error类型,表示一个错误。
panic内置函数,接收一个interface{}类型的值(也就是任何值了)作为参数。可以接收error类型的变量,输出错误信息,并退出程序。

func panic(v interface{})
内建函数panic停止当前Go程的正常执行。当函数F调用panic时,F的正常执行就会立刻停止。F中defer的所有函数先入后出执行后,F返回给其调用者G。G如同F一样行动,层层返回,直到该Go程中所有函数都按相反的顺序停止执行。之后,程序被终止,而错误情况会被报告,包括引发该恐慌的实参值,此终止序列称为恐慌过程。

//函数读取配置文件init.conf的信息
//如果文件名传入不正确就返回一个自定义错误
func readConf(name string) (err error) {
	if name == "config.ini" {
		//读取
		return nil
	} else {

		return errors.New("读取文件名错误")
	}
}
func test01() {
	// err := readConf("config1.ini")
	if readConf("config1.ini") != nil { // err != nil
		//读取文件发生错误,就输出自定义错误,并终止程序
		fmt.Println(readConf("config1.ini"))
		panic(readConf("config1.ini")) //panic(err)
	}
	fmt.Println("test()01继续执行")//不执行
}
func main() {
	//测试
	 test01()
	 fmt.Println("main()下面的代码")//不执行
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值