首页 > 其他分享 >Go03-函数+包+异常处理

Go03-函数+包+异常处理

时间:2024-03-18 17:37:30浏览次数:34  
标签:函数 int fmt Go03 a1 func Println 异常

Go03-函数+包+异常处理

1.函数的基本介绍

func main() {
	// 1 为完成某一功能的程序指令的集合,成为函数。
	// 2 函数分为自定义函数和系统函数。

	// 3 函数的定义,使用关键字func来定义一个函数。
	/*
	func 函数名 (形参列表) (返回值列表) {
		函数执行的语句
		return 返回值列表
	}
	 */
	a1 := test01(1)
	fmt.Println(a1) // 11
}

func test01(a int) int {
	return a + 10
}

2.包的基本介绍

  1. Go中每一个文件都属于一个包,Go是以包的形式管理文件和项目目录的。

  2. 包的作用:区分相同的函数、变量名;当程序文件很多时,可以更好的管理项目;控制函数、变量的访问范围,即作用域。

  3. 包的基本语法:打包语法,package 包名;引入包的基本语法,import 包的路径

  4. 包的基本使用

    1. $GOPATH/src/GoCode/GoDemo02/main/main.go。
    package main
    
    import (
        // 引入包,从GOPATH下引入包,src可以省略。
    	"GoCode/GoDemo02/utils"
    	"fmt"
    )
    
    func main() {
    	a := utils.Add(1, 2)
    	fmt.Println(a) // 3
    }
    
    1. $GOPATH/src/GoCode/GoDemo02/utils/add.go。
    package utils
    
    func Add(a int, b int) int {
    	return a + b
    }
    
  5. 包名通常和文件所在的文件夹名一致,如add.go在utils文件夹下,就package utils打为utils包;add.go在utils下,也可以打为其他包,如package abc,打为abc包,引入语句为import "GoCode/GoDemo02/abc",使用语句为abc.Add(1, 2)。

  6. 包名一般为小写字母,如果有多个小写字母使用_隔开。

  7. 引入包的两种方式:引入包的第一种方式,用于引入一个包,import "包名";引入包的第二种方式,用于引入多个包,import ( "包名" \n "包名")

  8. import导入包时,路径从$GOPATH的src开始,一般不需要不用写src,编译器会自动从src下开始寻找。

  9. 如果需要让其包访问到本包的函数或者变量,则包中的函数或者变量首字母需要大写,类似于其他编程语言中的public权限访问修饰符,这样才能进行跨包访问。

  10. 包名较长时,则可以给包取别名,去别名之后,就需要使用别名来访问包中的函数。

    1. 取别名import a "GoCode/GoDemo02/utils"
    2. 取别名之后访问包中的函数就需要使用别名来访问,a.Add(1, 2)
  11. 在同一个包下,不能有相同的函数名或者全局变量名,否则报重复定义的错误。理解:包中函数的调用语法是包名.函数名,如果有相同的函数名,则不知道调用的函数。即GoCode/GoDemo02/utils包下,可以有多个go文件,如add1.go、add2.go,但是utils包下所有的文件中只能有一个Add函数。

  12. 如果需要编译一个可执行文件,就需要将这个包声明为main包,这是一个语法规范;如果开发一个库文件,则包名可以自定义。

  13. D:\GOPATH>go build -o bin/my.exe GoCode/GoDemo02/main,go build的-o参数可以指定打包之后可执行文件的路径和名称。在GOPATH下打包,并将可执行文件放到GOPATH/bin下。

  14. go build打包时,会将引入的外部项目打包为.a文件,并且.a文件保存在pkd下。如将引入的redis打包为$GOPATH\pkg\windows_amd64\github.com\garyburd\redigo\redis.a

3.函数的参数和返回值

  1. 函数的return。
func main() {
	// 1 Go中的函数支持多个参数的返回值。
	// 在返回多个值时,如果希望忽略某个返回值,则使用_符号占位忽略。
	a1, a2 := test01()
	fmt.Println(a1, a2) // 2 3

	// 使用占位符忽略第一个返回值。
	_, a3 := test01()
	fmt.Println(a3) // 3

	// 2 当函数的返回值只有一个时,可以忽略返回值的()。
	a4 := test02()
	fmt.Println(a4) // 10
}

func test02() int {
	return 10
}

func test01() (int, int) {
	return 2, 3
}
  1. 函数的参数。
func main() {
	// 1 基本数据类型和数组都是值传递,即进行值拷贝。在函数内进行修改不会影响原值。
	s1 := "alice"
	test01(s1)
	fmt.Println(s1) // alice

	// 2 如果希望函数可以修改值类型的参数,可以传递变量的地址。
	s2 := "alice"
	test02(&s2)
	fmt.Println(s2) // tom

	// 3 Go中的函数不支持重载,即不支持同名函数。
}

// 报错。Go不支持函数的重载。
//func test02(a int)  {
//
//}

func test02(s *string) {
	*s = "tom"
}

func test01(s string) {
	s = "tom"
}
  1. 函数返回值命名。
func main() {
	// 1 Go支持对函数的返回值命名。
	a1 := test01(10, 10)
	fmt.Println(a1) // 20
}

func test01(a int, b int) (sum int) {
	sum = a + b
	return
}
  1. 可变参数。
func main()  {
	// 1 可变参数本质是slice切片,可以通过args[index]访问。
	// 2 如果函数中的形参中有可变参数,则可变参数需要写在最后。
	a1 := test01(1, 2, 3)
	fmt.Println(a1) // 6
}

func test01(a ...int) int {
	sum := 0
	for i := 0; i < len(a); i++ {
		sum += a[i]
	}

	// 可变参数for...range遍历。
	for index, value := range a{
		fmt.Println(index, value)
	}
	return sum
}

5.Go中函数也是一种数据类型

func main() {
	// 1 Go中函数也是一种数据类型,可以赋值给一个变量,
	// 则该变量就是一个函数类型的变量,并且该变量也可以像函数一样被调到。
	var a1 func(int, int) int = test01
	// a1的类型func(int, int) int,test01的类型func(int, int) int
	fmt.Printf("a1的类型%T,test01的类型%T\n", a1, test01)

	// 变量像函数一样调用,等价于a2 := test01(10, 20)
	a2 := a1(10, 20)
	fmt.Println(a2) // 30

	// 2 Go中函数也是一种数据类型,所以可以作为形参传递。
	a3 := test02(test01)
	fmt.Println(a3) // 20
}

func test02(a func(int, int) int) int {
	return a(10, 10)
}

func test01(a int, b int) int {
	return a + b
}

6.自定义数据类型

// 1 Go中支持自定义数据类型,可以将自定义数据类型理解为别名。
// 自定义数据语法:type 自定义数据类型名 数据类型
type myInt int
var a1 myInt = 10
// a1类型main.myInt,a1=10
fmt.Printf("a1类型%T,a1=%d\n", a1, a1)

// 2 自定义函数类型。
// a2的类型是func(int, int) int,太长了,可以使用自定义类型。
var a2 func(int, int) int = test01
// a2的类型func(int, int) int
fmt.Printf("a2的类型%T\n", a2)

type MyTest func(int, int) int
var a3 MyTest = test01
// main.MyTest
fmt.Printf("%T", a3)

7.init函数

  1. init函数。
func main() {
	// 1 Go中的init函数会在main函数前执行。
	// a b
	fmt.Println("b")
}

func init() {
	fmt.Println("a")
}
  1. init函数的执行顺序。
func main() {
	// 1 如果.go文件中同时存储全局变量、init函数、main函数,
	// 则执行顺序是:全局变量、init函数、main函数。

	/*
	全局变量执行。。。
	init函数执行。。。
	main函数开始执行。。。
	*/
	fmt.Println("main函数开始执行。。。")

	// 2 如果main.go和utils.go中都有init函数,main.go使用utils.go中的函数。
	// 则执行顺序是:utils.go中的全局变量、utils.go中的init函数、main.go中的全局变量、
	// main.go中的init函数、main.go中的main函数。
}

var a int = test01()

func test01() int {
	fmt.Println("全局变量执行。。。")
	return 1
}

func init() {
	fmt.Println("init函数执行。。。")
}

8.匿名函数

func main() {
	// 1 匿名函数使用方式一,定义匿名函数时就进行匿名函数的调用。
	// 这种匿名函数只能调用一次。
	a := func(a int, b int) int {
		return a + b
	}(10, 20)
	fmt.Println(a) // 30

	// 2 匿名函数使用方式二,将匿名函数赋值给某个变量,
	// 通过该变量来调用匿名函数,该方式定义的匿名函数可以被多次调用。
	b := func(a int, b int) int {
		return a + b
	}
	fmt.Println(b(10, 10)) // 20
	fmt.Println(b(20, 20)) // 40

	// 3 全局匿名函数,将一个匿名函数赋值给一个全局变量,则这个匿名函数,
	// 就成为了一个全局匿名函数。
	fmt.Println(c(5, 5)) // 25
}

var (
	c = func(a int, b int) int {
		return a * b
	}
)

9.闭包

  1. 闭包。
func main() {
	// 1 闭包就是一个函数和与其相关的应用环境组合的一个整体。
	// test01()的返回值是一个函数,这个函数和所拥有的test01()中的全部变量组成了闭包。
	// test01()返回的函数中应用的变量只会被初始化一次。
	a := test01()
	fmt.Println(a(1)) // 11
	fmt.Println(a(1)) // 12
}

func test01() func(int) int {
	a := 10
	return func(b int) int {
		a = a + b
		return a
	}
}
  1. 闭包练习。
func main() {
	a := makeSuffix(".jpg")
	fmt.Println(a("1.jpg"))
	fmt.Println(a("1.png"))
}

// 1 makeSuffix接受一个文件后缀名.jpg并返回一个闭包。
// 2 调用闭包,传入文件名,如果该文件名的后缀和传入的后缀.jpg相同,则返回原文件名;
// 如果该文件没有指定的后缀,则返回文件名+后缀名。
func makeSuffix(suffix string) func(fileName string) string	 {
	return func(fileName string) string {
		if strings.HasSuffix(fileName, suffix) {
			return fileName
		}

		return fileName + suffix
	}
}

10.函数的defer

func main() {
	// 1 defer在函数执行完成之后执行某些语句,如函数执行完成之后释放资源。
	// 2 当执行到defer时,不会立即执行defer后的语句,而是将defer压入栈中,
	// 然后继续执行后面的语句。当函数执行完成后,依次从栈顶取出语句执行。
	/*
	test01
	defer02
	defer01
	 */
	test01()

	// 3 将defer语句压入栈中时,会将相关的值拷贝到栈中。
	/*
	10 20
	11 21
	b= 20
	a= 10
	 */
	test02(10, 20)
}

func test02(a int, b int)  {
	defer fmt.Println("a=", a)
	defer fmt.Println("b=", b)

	fmt.Println(a, b)
	a++
	b++
	fmt.Println(a, b)
}

func test01() {
	defer fmt.Println("defer01")
	defer fmt.Println("defer02")

	fmt.Println("test01")
}

11.函数的参数传递

  1. 两种参数传递的方式:值传递和引用传递。
  2. 不管是值传递还是引用传递,传递的都是变量的副本。不同的是,值传递的是值的副本拷贝;引用传递的是地址的副本拷贝。一般来说,地址拷贝效率高,因为数据量小。
  3. 值类型的数据有:基本数据类型int系列、float系列、string、bool、数组和结构体;引用类型的数据有:指针、slice切片、map、管道chan、interface。
  4. 值类型默认是值传递,变量直接存储值,内存通常在栈中分配。
  5. 引用类型默认是引用传递,变量存储的是一个地址,变量对应的地址存储真正的数据,内存通常在堆上分配。当没有没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收。
  6. 如果希望函数内的变量可以修改函数外值类型的数据,可以传入值类型变量的地址&,函数以指针的方式操作变量。

12.字符串相关的函数

// 1 len()统计字符串的长度,按字节。一个英文和数字占一个字节,一个汉字占三个字节。
a1 := "1中"
fmt.Println(len(a1)) // 4

// 2 []rune(),处理字符串遍历时中文乱码问题。
a2 := "1中"
// 1	ä	¸	­
for i := 0; i < len(a2);i++ {
    fmt.Printf("%c\t", a2[i])
}

fmt.Println()
a3 := []rune(a2)
// 1	ä	¸	­
for i := 0;i < len(a3);i++ {
    fmt.Printf("%c\t", a3[i])
}

fmt.Println()
// 3 字符串转整数。
a4, _ := strconv.Atoi("12")
fmt.Println(a4) // 12

// 4 整数转字符串。
a5 := strconv.Itoa(123)
fmt.Println(a5) // 123

// 5 字符串转[]byte数组
a6 := []byte("hello 张三")
// [104 101 108 108 111 32 229 188 160 228 184 137]
fmt.Println(a6)

// 6 byte转字符串。
a7 := []byte{97, 98, 99}
a8 := string(a7)
fmt.Println(a8) // abc

// 7 十进制转2、8、16进制。
fmt.Println(strconv.FormatInt(10, 2)) // 1010
fmt.Println(strconv.FormatInt(10, 8)) // 12
fmt.Println(strconv.FormatInt(10, 16)) // a

// 8 查找子串是否在指定的字符串中。
fmt.Println(strings.Contains("hello", "ll")) // true

// 9 统计字符串包含几个指定的子串。
fmt.Println(strings.Count("hello hello hello", "ll")) // 3

// 10 字符串比较。
b1 := "hello"
b2 := "HeLLo"
b3 := "hello"
// ==在比较字符串时,区分大小写
fmt.Println(b1 == b2) // false
fmt.Println(b1 == b3) // true

// strings.EqualFold()不区分大小写比较字符串。
fmt.Println(strings.EqualFold(b1, b2)) // true

// 11 子串查找,如果包含子串,则返回子串第一次出现的索引;如果不包含子串,则返回-1。
fmt.Println(strings.Index("hello", "ll")) // 2
fmt.Println(strings.Index("hello", "k")) // -1

// 12 返回子串最后一次出现的位置,没有找到字符返回-1。
fmt.Println(strings.LastIndex("hello", "e")) // 1
fmt.Println(strings.LastIndex("hello", "m")) // -1

// 13 字符串替换。
// strings.Replace(),最后一个参数n表示,要替换字符串的个数,-1表示替换所有。
// hemmo hello
fmt.Println(strings.Replace("hello hello", "ll", "mm", 1))
// hemmo hemmo
fmt.Println(strings.Replace("hello hello", "ll", "mm", -1))

// 14 字符串切割,将字符串按照指定字符切割为数组。
// [hello hello]
fmt.Println(strings.Split("hello,hello", ","))

// 15 字符串转大写和小写。
// 转小写 hello
fmt.Println(strings.ToLower("HeLLO"))
// 转大写 HELLO
fmt.Println(strings.ToUpper("hello"))

// 16 去掉字符串两边的空格。
fmt.Println(strings.TrimSpace(" hello ")) // hello

// 17 Trim的其中用法。
// 去掉字符串两边的指定字符。hello
fmt.Println(strings.Trim(",hello,", ","))
// 去掉字符串左边指定字符。,hello
fmt.Println(strings.TrimLeft("1,hello", "1"))
// 去掉字符串右边指定字符。hello,
fmt.Println(strings.TrimRight("hello,1", "1"))

// 18 判断字符串是否以指定字符开头。
fmt.Println(strings.HasPrefix("hello", "h")) // true

// 19 判断字符串是否以指定字符串结尾。
fmt.Println(strings.HasSuffix("hello", "o")) // true

13.时间和日期相关的函数

// 1 获取当前时间,time.Time用于表示时间类型。
a1 := time.Now();
// 2023-01-07 15:40:20.9207375 +0800 CST m=+0.002348001,type=time.Time
fmt.Printf("%v,type=%T\n", a1, a1)

// 2 获取日期的年月日时分秒信息。
fmt.Printf("年=%v\n", a1.Year()) // 年=2023
fmt.Printf("月=%v\n", a1.Month()) // 月=January
// Month(),返回的是Month类型,可以转换为int。
fmt.Printf("月=%v\n", int(a1.Month())) // 月=1
fmt.Printf("日=%v\n", a1.Day()) // 日=7
fmt.Printf("时=%v\n", a1.Hour()) // 时=15
fmt.Printf("分=%v\n", a1.Minute()) // 分=51
fmt.Printf("秒=%v\n", a1.Second()) // 秒=0

// 3 日期时间格式化方式一。
a2 := time.Now()
// 当前时间 2023-1-7 16:19:58
fmt.Printf("当前时间 %d-%d-%d %d:%d:%d\n", a2.Year(),
           a2.Month(), a2.Day(), a2.Hour(), a2.Minute(), a2.Second())

a3 := fmt.Sprintf("当前时间 %d-%d-%d %d:%d:%d\n", a2.Year(),
                  a2.Month(), a2.Day(), a2.Hour(), a2.Minute(), a2.Second())
fmt.Printf(a3)

// 3 日期时间格式格式化方式二。
a4 := time.Now()
// Format()的参数2006-01-02 15:04:05是固定的,必须这样写。
// 2023-01-07 16:27:21
fmt.Printf(a4.Format("2006-01-02 15:04:05"))
fmt.Println()
// 2023-01-07
fmt.Printf(a4.Format("2006-01-02"))
fmt.Println()
// 16:27:21
fmt.Printf(a4.Format("15:04:05"))
fmt.Println()

// 4 time中的时间常量。
minute := time.Minute
// 10分钟
fmt.Println(10 * minute) // 10m0s


// 5 Sleep的使用,每个一秒打印一个数字,打印到3退出。
a5 := 0
// 0 1 3
for  {
    fmt.Println(a5)
    time.Sleep(1 * time.Second)
    a5++
    if a5 == 3 {
        break
    }
}

// 6 Unix()和UnixNano()
a6 := time.Now()
// Unix()返回从1970年1月1日到时间点所经过的时间,单位秒。
fmt.Println(a6.Unix()) // 1673081313
// UnixNano()返回从1970年1月1日到时间点所经过的时间,单位纳秒;
// UnixNano()返回值类型是int64,如果返回值范围超过int64,结果时未定义的。
fmt.Println(a6.UnixNano()) // 1673081313761040800

14.new和make分配内存

// 1 new用来给值类型分配内存,比如,int系列、float系列、string、bool、数组和struct。
// new()返回一个指针,这个指针指向new分配的内存。
a1 := new(int)
*a1 = 100

// a1的地址 0xc000006028
fmt.Println("a1的地址", &a1)
// a1的值 0xc00000a0a8
fmt.Println("a1的值", a1)
// a1地址对应的值 100
fmt.Println("a1地址对应的值", *a1)

// 2 make可以给引用类型分配内存,比如给channel、map、slice分配内存。

15.异常处理

func main() {
	// 1 当程序报错后,会由于异常而退出,如果想不退出就需要进行异常处理。
	// 报错:panic: runtime error: integer divide by zero
	// test01()
	fmt.Println("程序继续执行")

	// 2 Go中可以通过panic抛出异常,然后再defer中通过recover来捕获异常。
	test02()
	fmt.Println("程序继续执行。。。")

	// 3 自定义错误。使用errors.New()和panic内置函数完成自定义错误。
	// errors.New("xxx错误")会返回一个error类型值,这个值表示一个错误。
	// panic内置函数可以接受一个interface{}类型的值(interface{}类型的值可以理解为任何值)作为参数。
	// panic接受error类型的变量后会输出错误信息,并退出程序。

	// test03继续执行
	test03("init.config")
	// 报错打印panic: 文件名错误,并且退出程序的执行,不会输出test03继续执行。
	test03("init1.config")
}

// 读取init.config配置文件的信息,如果文件名不是init.config则报错。
func readFile(fileName string) error {
	if fileName == "init.config" {
		return nil
	} else {
		return errors.New("文件名错误")
	}
}

func test03(fileName string) {

	err := readFile(fileName)
	if err != nil {
		panic(err)
	}
	fmt.Println("test03继续执行")
}

func test02() {
	// 使用defer + recover来捕获异常。
	defer func() {
		// recover是系统内置函数,可以捕获到运行时抛出的异常。
		error := recover()
		fmt.Println(error)
		if error != nil {
			fmt.Println("捕获到异常", error)
		}
	}()

	a1 := 10
	a2 := 0
	fmt.Println(a1 / a2)
}

func test01() {
	a1 := 10
	a2 := 0
	fmt.Println(a1 / a2)
}

标签:函数,int,fmt,Go03,a1,func,Println,异常
From: https://www.cnblogs.com/godistance/p/17258512.html

相关文章

  • stm32库函数_小知识
    stm32库函数值计算#definePOSITION_VAL(VAL)(__CLZ(__RBIT(VAL)))在STM32中的作用是计算指定值VAL在二进制表示中最高位的位置。这里使用了一些内置的CMSIS函数,包括__RBIT(反转位顺序)和__CLZ(计算前导零位数)。解释:__RBIT(VAL):反转VAL的位顺序。例如,如果VAL的二进......
  • 虚函数以及类的强制转换
    虚函数类的对象模型classA{public:voidf1(){}voidf2(){}virtualvoidf3(){}virtualvoidf4(){}};classB{public:voidf1(){}voidf2(){}};classC{};intmain(){Aa;Bb;Cc;std::cout<<sizeof(a)<......
  • 函数式编程
    1.持久化数据结构    持久化数据结构的含义是,对于每一个调用者来说,他所使用的每一个数据结构已经持久化了(不可变了),例如f(x)=y,g(y)=z,x、y和z的数据结构已经持久化了,就算其他地方如何去使用,x、y和z都不能有变化。    比如说调用者拥有树1,调用一个方法需要更新树1,那么此时......
  • SQL中的COUNT函数:深入理解COUNT(*)、COUNT(1)和COUNT(字段)的异同与应用
    SQL中的COUNT函数是一个非常强大的聚合函数,它可以用来统计表中满足特定条件的行数。COUNT函数有三种不同的用法:COUNT(*)、COUNT(1)和COUNT(字段),每种用法都有其特定的用途和性能考虑。COUNT(*)COUNT(*)用于统计表中的所有行,不论这些行的值是否为NULL。当你想要得到表中总行数时,......
  • 配置全局变量直接调用函数
    配置全局变量直接调用函数目的想要在项目中使用defs.utills.getFunction()的方式,直接调用我们的函数,不再使用import的方式进行导入,直接在工程化上做手脚进行自动导入解决。过程首先我们在我们的项目框架src/目录下定义一个全局的utill文件,这个我们可以分类型创建文件夹、......
  • C++中的this指针、访问控制和构造函数
    C++中的this指针、访问控制和构造函数this指针在C++中,this指针是一个特殊的指针,它指向当前对象的地址。每个非静态成员函数(包括成员函数模板)都有一个this指针作为其隐含参数,这意味着在成员函数内部,this可以用来引用调用该成员函数的对象。this指针是自动传递给成员函数的,......
  • 文件描述符(File Descriptor, FD)和 poll 函数简介
    文件描述符(FileDescriptor,FD)是Unix和类Unix操作系统中用于标识进程打开的文件、设备或其他I/O资源的一个抽象概念。它是一个非负整数,由内核在进程打开或创建一个文件时分配给该进程。当应用程序通过系统调用如open()、socket()等操作打开一个现有文件、创建新文件或者创......
  • 已解决org.apache.zookeeper.KeeperException.SessionExpiredException异常的正确解决
    已解决org.apache.zookeeper.KeeperException.SessionExpiredException异常的正确解决方法,亲测有效!!!目录问题分析报错原因解决思路解决方法总结 博主v:XiaoMing_JavaApacheZooKeeper是一个开源的分布式协调服务,它被广泛用于维护配置信息、命名注册、提供分布式同步......
  • 内存函数(C语言)
    文章目录内存函数memcpymemmovememsetmemcmp内存函数使用内存函数需要包含头文件<string.h>memcpy将内存的数据拷贝到新空间void*memcpy(void*destination,constvoid*source,size_tnum);memcpy函数能将源地址后num个字节的数据拷贝到目标空间区别内存......
  • 字符函数和字符串函数
    文章目录字符函数和字符串函数字符函数字符分类函数字符转换函数字符串函数strlenstrcpystrcatstrcmpstrncpystrncatstrncmpstrstrstrtokstrerror字符函数和字符串函数字符函数下面介绍的函数均包含在头文件<ctype.h>中字符分类函数字符分类函数帮你判断一个......