go-包(函数、域)

go-包(函数、域)

func main() {

	var num1 float64
	var num2 float64
	var operator byte
	num1 = 1.2
	num2 = 1.3
	operator = '+'
	// fmt.Scanln(&num1)
	// fmt.Scanln(&operator) // 这里输入错误
	fmt.Scanf("%f %c %f", &num1, &operator, &num2)
	var res float64 = cal(num1, num2, operator)
	fmt.Printf("%f %c %f = %v\n", num1, operator, num2, res)

}

func cal(num1 float64, num2 float64, operator byte) float64 {
	var ans float64
	switch operator {
	case '+':
		ans = num1 + num2
	case '-':
		ans = num1 - num2
	case '*':
		ans = num1 * num2
	case '/':
		ans = num1 / num2
	}
	return ans
}

  1. 区分相同名字的函数、变量等标识符
  2. 当程序文件很多时,可以很好的管理项目
  3. 控制函数、变量等访问范围,即作用域
package main

import (
	"fmt"
	"go_code/Study_go/Study_go_six/demo02/utils_test"
)

func main() {
	num1 := 10.5
	num2 := 11.5
	num3 := 12.5
	opt := '+'
	res := utils_test.Cal(num1, num2, byte(opt))
	ans := utils_test.AddNum(num1, num2, num3)
	fmt.Printf("res: %v\n", res)
	fmt.Printf("ans: %v\n", ans)
  fmt.Printf("utils_test.Num: %v\n", utils_test.Num)
}


package utils_test

func AddNum(num1 float64, num2 float64, num3 float64) float64 {
	return num1 + num2 + num3
}


package utils_test

var Num float64 = 1.1

func Cal(num1 float64, num2 float64, opt byte) float64 {
	var ans float64 = 0
	switch opt {
	case '+':
		ans = num1 + num2
	case '-':
		ans = num1 - num2
	case '*':
		ans = num1 * num2
	case '/':
		ans = num1 / num2
	}
	return ans
}

注意事项

  1. 在给一个文件打包时,该包对应一个文件件,文件的包名通常和文件所在的文件夹名保持一致
  2. 当一个文件要使用其他包函数或变量时,需要先引入对应的包
  3. package指令在文件第一行,然后是import指令
  4. 在import引入时,路径从$GOPATH和$GOROOT的src下开始,不用带src,编译器会自动从src下开始引入
  5. 为了让其他包的文件,可以访问到本包的函数,则该函数名的首字母需要大写,类似其他语言的public,这样才能跨包访问
  6. 在访问其他包函数的变量时,其语法是 包名.函数名
  7. 当包名很长时,可以使用别名,使用别名后,原名则会失效
  8. 在同一个包下,不能有相同的函数名,否则会报重复定义
  9. 若要编译成一个可执行文件,就需要将这个包声明为main包,main包只能有一个,就是一个语法规范

image-20220418110823460

函数

注意事项和细节

  1. 函数的形参列表可以是多个,返回值列表也可以是多个
  2. 形参列表和返回值列表的数据类型可以是值类型和引用类型
  3. 函数的命名遵循标识符命名规范,首字母不能是数字,首字母大写该函数可以被本包文件和其他文包文件使用,类似public,首字母小写,只能被本包文件使用,其他包文件不能使用,类似private
  4. 函数中的变量是局部的,函数外不能生效
  5. 基本数据类型和数组默认都是值传递,即进行值拷贝。在函数内修改,不会影响到原来的值
  6. 若希望函数内的表里能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。
  7. go函数不支持重载
  8. golang中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量
  9. 函数既然是一种数据类型,因此在go中,函数可以作为形参,并且调用
  10. 为了简化数据类型定义,go支持自定义数据类型
  11. 支持对函数返回值命名
  12. 使用_占位符,忽略某个返回值
  13. go支持可变参
// 10. 自定义数据类型 类似于别名
type myFunc func(int, int) (int, int)

func main() {

	// 6. 地址传递
	var num int = 10
	fmt.Printf("num: %v\n", num) // 10
	test2(&num)
	fmt.Printf("num: %v\n", num) // 20

	// 8. 函数作为数据类型
	var a = test1
	fmt.Printf("a: %T\n", a)         // a: func(int, int) (int, int)
	fmt.Printf("test1: %T\n", test1) // test1: func(int, int) (int, int)
	sum, sub := a(10, 20)
	fmt.Printf("sum: %v\t  sub: %v\n", sum, sub) // sum: 30   sub: -10

	// 9. 函数作为形参
	sum1, sub1 := test3(a, 20, 30)
	fmt.Printf("sum1: %v\t  sub1: %v\n", sum1, sub1) // sum1: 50   sub1: -10

	// 10. 自定义数据类型 类似于别名
	type myInt int
	var b myInt = 10
	fmt.Printf("b: %v\n", b) // 10
	sum2, sub2 := test4(test1, 500, 600)
	fmt.Printf("sum2: %v\tsub2: %v\n", sum2, sub2) // sum2: 1100      sub2: -100

	// 11. 函数返回值命名 func test1(num1 int, num2 int) (sum int, sub int) {

	// 13. 可变参:可变参数放在固定参数后面
	sum5 := test5(10, 20, 30, 40, 50)
	fmt.Printf("sum5: %v\n", sum5) // sum5: 150

}

func test1(num1 int, num2 int) (sum int, sub int) {
	sum = num1 + num2
	sub = num1 - num2
	return
}

func test2(num *int) {
	*num += 10
	fmt.Printf("num: %v\n", *num) // 20
}

func test3(funvar func(int, int) (int, int), num1 int, num2 int) (int, int) {
	return funvar(num1, num2)
}

func test4(funvar myFunc, num1 int, num2 int) (int, int) {
	return funvar(num1, num2)
}

func test5(nums ...int) (sum int) {
	for i := 0; i < len(nums); i++ {
		sum += nums[i]
	}
	return
}

底层调用机制

image-20220418114605688

package main

import (
   "fmt"
   "go_code/Study_go/Study_go_six/demo03/functiondemo"
)

func main() {
   var num int = 10
   test1 := functiondemo.AddOne(num)
   fmt.Printf("num: %v\n", num)       // 10
   fmt.Printf("test1: %v\n", test1)   // 11
   test2 := functiondemo.AddTwo(&num) // 传递参数地址过去
   fmt.Printf("num: %v\n", num)       // 11 形参地址的值已经变为11
   fmt.Printf("test2: %v\n", test2)   // 11
 
 var num1 int = 5
   var num2 int = 3
   test3, test4 := functiondemo.AddAndSub(num1, num2)
   fmt.Printf("test3: %v\n", test3)               // 8
   fmt.Printf("test4: %v\n", test4)               // 2
   test5, _ := functiondemo.AddAndSub(num1, num2) // 8
   fmt.Printf("test5: %v\n", test5)
   _, test6 := functiondemo.AddAndSub(num1, num2) // 2
   fmt.Printf("test6: %v\n", test6)
 
}

package functiondemo

func AddOne(num int) int {
   num++
   return num
}

func AddTwo(num *int) int {
   *num++
   return *num
}

// 计算两数加和减, 返回两者的结果
func AddAndSub(num1 int, num2 int) (int, int) {
   res1 := num1 + num2
   res2 := num1 - num2
   return res1, res2
}

递归函数

  1. 一个函数在函数体内又调用了本身,成为递归调用
  2. 执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
  3. 函数的局部变量是独立的,不会相互影响
  4. 递归必须向退出递归的条件逼近,否则就是无限循环
  5. 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当函数执行完毕后,该函数栈会被系统销毁
func main() {
	res1 := f1(5)
	fmt.Printf("res1: %v\n", res1) // 120

	res2 := f2(5)
	fmt.Printf("res2: %v\n", res2) // 8
}

// n!
func f1(num int) int {
	if num == 0 || num == 1 {
		return 1
	}
	return num * f1(num-1)
}

// 斐波那契
func f2(num int) int {
	if num == 0 || num == 1 {
		return 1
	}
	return f2(num-1) + f2(num-2)
}

init函数

  1. 每个源文件都可以包含一个init函数,该函数会在main函数执行前,被go运行框架调用,也就说init会在main函数前被调用
  2. 若一个文件同时包括全局变量定义、init函数、main函数,则执行的流程是 变量定义 --> init函数 – > main函数
  3. init函数最主要的作用,就是完成一些初始化工作
  4. 被引入文件变量定义 --> 被引入文件init函数 --> 本文件变量定义 --> 本文件init函数 --> 本文件main函数
package main

import (
	"fmt"
	temptest "go_code/Study_go/Study_go_six/demo06/tempTest"
)

// 输出结果:
// temptest test
// temptest init
// test function
// init function
// main function
// val: 90
// temptest.Name: wxy
// temptest.Age: 22
var val int = test()

func main() {
	fmt.Println("main function")
	fmt.Printf("val: %v\n", val)
	fmt.Printf("temptest.Name: %v\n", temptest.Name)
	fmt.Printf("temptest.Age: %v\n", temptest.Age)
}

// 用于完成初始化操作
func init() {
	fmt.Println("init function")
}

func test() int {
	fmt.Println("test function")
	return 90
}


package temptest

import "fmt"

var Name string = test()
var Age int

func test() string {
	fmt.Println("temptest test")
	return "wxy"
}

func init() {
	Age = 22
	fmt.Println("temptest init")
}

匿名函数

  1. go支持匿名函数,若某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用
func main() {
	// 方式1
	res1 := func(n1 int, n2 int) int {
		return n1 + n2
	}(10, 20)
	fmt.Printf("res1: %v\n", res1) // res1: 30

	// 方式2  基本不用
	a := func(n1 int, n2 int) int {
		return n1 - n2
	}
	res2 := a(10, 20)
	fmt.Printf("res2: %v\n", res2) // res2: -10
	// 多次调用
	res3 := a(30, 10)
	fmt.Printf("res3: %v\n", res3) // res3: 10

	// 3. 调用全局匿名函数
	res4 := Fun1(10, 20)
	fmt.Printf("res4: %v\n", res4) // res4: 200
}

// 3. 全局匿名函数
var (
	// 首字母需要大写
	Fun1 = func(num1 int, num2 int) int {
		return num1 * num2
	}
)

闭包

  1. 闭包是一个函数与其他引用的整体组成的实体
/*
	1. AddUpper 是一个函数,返回的类型是 func(int) int
	2. 闭包的说明:
			var n int = 10
			return func(i int) int {  返回一个匿名函数,但是这个匿名函数引用到函数外的n,
				因此和这个匿名函数就和n形成了一个整体,构成闭包
				n = n + i
				return n
			}
	3. 闭包类似于类,函数是操作,n是字段。函数和它一起组成闭包
	4. 当反复调用f时,因为n初始化一次,因此每调用一次就会进行累加,不再进行初始化
	5. 关键是分析出返回的函数它使用了(引用)到那些变量

*/

func AddUpper() func(int) int {

	var n int = 10
	var str string = "hello"
	return func(i int) int {
		n = n + i
		str += "a"
		fmt.Printf("str: %v\n", str)
		return n
	}
}

func main() {
	res := AddUpper()
	fmt.Printf("res: %T\n", res)    // res: func(int) int
	fmt.Printf("res: %v\n", res(1)) // 11
	fmt.Printf("res: %v\n", res(2)) // 13
	fmt.Printf("res: %v\n", res(3)) // 16
}
import (
	"fmt"
	"strings"
)

func makeSuffix(suffix string) func(str string) string {

	return func(str string) string {
		if strings.HasSuffix(str, suffix) {
			return str
		} else {
			return str + suffix
		}
	}

}

func makeSuffix2(suffix string, str string) string {

	if strings.HasSuffix(str, suffix) {
		return str
	} else {
		return str + suffix
	}

}

func main() {
	test := makeSuffix(".jpg")
	fileName := test("abc")
	fmt.Printf("fileName: %v\n", fileName) // fileName: abc.jpg

	fmt.Printf("makeSuffix2(fileName, \"jpg\"): %v\n", makeSuffix2(".jpg", "name"))
	//makeSuffix2(fileName, "jpg"): name.jpg
}

defer

/*
	输出结果
	sum: 26
	n2 =  5
	n1 =  1
	res: 26
*/
func sum(n1 int, n2 int) (sum int) {
	// 当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer)
	// 当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行
	// 		在调用数据库时,会执行很多资源,但是需要在最后进行关闭资源
	//  	若使用defer的话,即可在调用完直接编写关闭资源
	//		这样会更方便
	defer fmt.Println("n1 = ", n1) // 1
	defer fmt.Println("n2 = ", n2) // 5
	n1 += 10
	n2 += 10
	sum = n1 + n2
	fmt.Printf("sum: %v\n", sum) // 26
	return
}

func main() {
	res := sum(1, 5)
	fmt.Printf("res: %v\n", res) // 26
}

  1. 函数内声明/定义的变量,叫局部变量,作用域仅限于函数内部
  2. 函数外部声明/定义的变量,叫全局变量,作用域在整个包都有效,若其首字母大写,则作用域在整个程序有效
  3. 若变量是在一个代码块,比如for中的i,那么这个变量的作用域就在该代码块有效

其他函数

字符串函数

strings

func Clone(s string) string

​ Clone returns a fresh copy of s

func Compare(a, b string) int

​ Compare returns an integer comparing two strings lexicographically. The result will be 0 if a == b, -1 if a < b, and +1 if a > b.

func Contains(s, substr string) bool

​ Contains reports whether substr is within s.

func ContainsAny(s, chars string) bool

​ ContainsAny reports whether any Unicode code points in chars are within s.

func ContainsRune(s string, r rune) bool

​ ContainsRune reports whether the Unicode code point r is within s.

func Count(s, substr string) int

​ Count counts the number of non-overlapping instances of substr in s. If substr is an empty string, Count returns 1 + the number of Unicode code points in s.

func EqualFold(s, t string0) bool

​ EqualFold reports whether s and t, interpreted as UTF-8 strings, are equal under Unicode case-folding, which is a more general form of case-insensitivity.

func Fields(s string) []string

​ Fields splits the string s around each instance of one or more consecutive white space characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an empty slice if s contains only white space.

func FieldsFunc(s string, f func(rune) bool) []string

​ FieldsFunc splits the string s at each run of Unicode code points c satisfying f© and returns an array of slices of s. If all code points in s satisfy f© or the string is empty, an empty slice is returned.

func HasPrefix(s, prefix string) bool

func HasPrefix(s, prefix string) bool

​ HasPrefix tests whether the string s begins with prefix. HasSuffix tests whether the string s ends with suffix.

func Index(s, substr string) int

​ Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.

func IndexAny(s, chars string) int

func IndexRune(s string, r rune) int

func IndexFunc(s string, f func(rune) bool) int

func IndexByte(s string, c byte) int

​ IndexRune returns the index of the first instance of the Unicode code point r, or -1 if rune is not present in s. If r is utf8.RuneError, it returns the first instance of any invalid UTF-8 byte sequence.

func Join(elems []string, sep string) string

​ Join concatenates the elements of its first argument to create a single string. The separator string sep is placed between elements in the resulting string.(将字符串数组以sep为分割符联合成一个字符串)

func LastIndex(s, substr string) int

func LastIndexAny(s, chars string) int

func LastIndexByte(s string, c byte) int

func LastIndexFunc(s string, f func(rune) bool) int

​ LastIndex returns the index of the last instance of substr in s, or -1 if substr is not present in s.

func Repeat(s string, count int) string

​ Repeat returns a new string consisting of count copies of the string s.

func Replace(s, old, new string, n int) string

​ Replace returns a copy of the string s with the first n non-overlapping instances of old replaced by new. If old is empty, it matches at the beginning of the string and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune string. If n < 0, there is no limit on the number of replacements.

func ReplaceAll(s, old, new string) string

​ ReplaceAll returns a copy of the string s with all non-overlapping instances of old replaced by new. If old is empty, it matches at the beginning of the string and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune string.

func Split(s, sep string) []string

​ Split slices s into all substrings separated by sep and returns a slice of the substrings between those separators.

​ If s does not contain sep and sep is not empty, Split returns a slice of length 1 whose only element is s.

​ If sep is empty, Split splits after each UTF-8 sequence. If both s and sep are empty, Split returns an empty slice.

​ It is equivalent to SplitN with a count of -1.

​ To split around the first instance of a separator, see Cut.

func ToLower(s string) string

func ToUpper(s string) string

func ToTitle(s string) string

​ ToUpper returns s with all Unicode letters mapped to their upper case.

func Trim(s, cutset string) string

​ Trim returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed.

strconv

func Atoi(s string) (int, error)

func Itoa(i int) string

​ Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.

​ Itoa is equivalent to FormatInt(int64(i), 10).

func FormatBool(b bool) string

​ FormatBool returns “true” or “false” according to the value of b.

func FormatFloat(f float64, fmt byte, prec, bitSize int) string

​ FormatFloat converts the floating-point number f to a string, according to the format fmt and precision prec. It rounds the result assuming that the original was obtained from a floating-point value of bitSize bits (32 for float32, 64 for float64).

​ The format fmt is one of ‘b’ (-ddddp±ddd, a binary exponent), ‘e’ (-d.dddde±dd, a decimal exponent), ‘E’ (-d.ddddE±dd, a decimal exponent), ‘f’ (-ddd.dddd, no exponent), ‘g’ (‘e’ for large exponents, ‘f’ otherwise), ‘G’ (‘E’ for large exponents, ‘f’ otherwise), ‘x’ (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or ‘X’ (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).

​ The precision prec controls the number of digits (excluding the exponent) printed by the ‘e’, ‘E’, ‘f’, ‘g’, ‘G’, ‘x’, and ‘X’ formats. For ‘e’, ‘E’, ‘f’, ‘x’, and ‘X’, it is the number of digits after the decimal point. For ‘g’ and ‘G’ it is the maximum number of significant digits (trailing zeros are removed). The special precision -1 uses the smallest number of digits necessary such that ParseFloat will return f exactly.

func FormatInt(i int64, base int) string

​ FormatInt returns the string representation of i in the given base, for 2 <= base <= 36. The result uses the lower-case letters ‘a’ to ‘z’ for digit values >= 10.

func FormatUint(i uint64, base int) string

​ FormatUint returns the string representation of i in the given base, for 2 <= base <= 36. The result uses the lower-case letters ‘a’ to ‘z’ for digit values >= 10.

func ParseBool(str string) (bool, error)

​ ParseBool returns the boolean value represented by the string. It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Any other value returns an error.

func ParseFloat(s string, bitSize int) (float64, error)

func ParseInt(s string, base int, bitSize int) (i int64, err error)

func ParseUint(s string, base int, bitSize int) (uint64, error)

时间日期函数(其他看API文档)

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	// 1. 获取当前时间
	now := time.Now()
	fmt.Printf("now: %v\n  %T \n", now, now)

	// 2. 获取当前时间的年月日 时分秒
	year := now.Year()
	fmt.Printf("year: %v\n", year)
	month := now.Month()
	fmt.Printf("month: %v\n", month)
	day := now.Day()
	fmt.Printf("day: %v\n", day)
	hour := now.Hour()
	fmt.Printf("hour: %v\n", hour)
	minute := now.Minute()
	fmt.Printf("minute: %v\n", minute)
	second := now.Second()
	fmt.Printf("second: %v\n", second)

	// 3. 格式化日期和时间 2006 01 02 15 04 05 固定写法
	s1 := now.Format("2006-01-02 15:04:05")
	s2 := now.Format("2006 - 01 - 02")
	s3 := now.Format("15 : 04 : 05")
	fmt.Printf("s1: %v\n", s1)
	fmt.Printf("s2: %v\n", s2)
	fmt.Printf("s3: %v\n", s3)
	// 4. time中的常量
	fmt.Printf("time.Nanosecond: %v\n", time.Nanosecond)   // time.Nanosecond: 1ns
	fmt.Printf("time.Microsecond: %v\n", time.Microsecond) // time.Microsecond: 1µs
	fmt.Printf("time.Millisecond: %v\n", time.Millisecond) // time.Millisecond: 1ms
	fmt.Printf("time.Second: %v\n", time.Second)           // time.Second: 1s
	fmt.Printf("time.Minute: %v\n", time.Minute)           // time.Minute: 1m0s
	fmt.Printf("time.Hour: %v\n", time.Hour)               // time.Hour: 1h0m0s
	for i := 0; i < 100; i++ {
		fmt.Printf("i: %v\t", i)
		time.Sleep(time.Millisecond * 10) // 时间常量不能使用float
	}

	// 4. 获取时间戳
	fmt.Printf("now.Unix(): %v\n", now.Unix())         // now.Unix(): 1650337607
	fmt.Printf("now.UnixNano(): %v\n", now.UnixNano()) // now.UnixNano(): 1650337607734718000

	for i := 0; i < 10; i++ {
		t := now.UnixNano()
		rand.Seed(t)
		num := rand.Intn(10) + 1
		fmt.Printf("num: %v\n", num)
	}
	// 5. 时间
	start := time.Now().Unix()
	for i := 0; i < 1000; i++ {
		time.Sleep(time.Millisecond)
	}
	end := time.Now().Unix()
	costTime := end - start
	fmt.Printf("costTime: %v\n", costTime)
}

内置函数

len()
func len(v Type) int

内建函数len返回 v 的长度,这取决于具体类型:

数组:v中元素的数量
数组指针:*v中元素的数量(v为nilpanic)
切片、映射:v中元素的数量;若v为nillen(v)即为零
字符串:v中字节的数量
通道:通道缓存中队列(未读取)元素的数量;若v为 nillen(v)即为零
new()
func new(Type) *Type

内建函数new分配内存。其第一个实参为类型,而非值。其返回值为指向该类型的新分配的默认值的指针。


func main() {
	var num int = 10
	// num: 10          int     0xc0000b2008
	fmt.Printf("num: %v \t %T \t %v \n", num, num, &num)

	num1 := new(int) // 分配内存--指针
	*num1 = 10
	// num1: 0xc0000b2018       *int    0xc0000ac020    10
	fmt.Printf("num1: %v \t %T \t %v \t %v \n", num1, num1, &num1, *num1)
	num2 := new(int)
	num2 = &num
	*num2 = 20
	fmt.Printf("num2: %v\t %v\n", *num2, num2) // num2: 20      0xc0000160a0
}
make()
func make(Type, size IntegerType) Type

内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:

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

错误处理机制errors

  1. go不支持传统的try…catch…finally
  2. go引入了defer panic recover
  3. go中可以抛出一个panic异常,然后在defer中通过recover捕获这个异常
func New(text string) error

使用字符串创建一个错误,请类比fmt包的Errorf方法,差不多可以认为是New(fmt.Sprintf(...))import (
	"errors"
	"fmt"
)


func test() {
	// 延迟处理
	defer func() { // 你们函数
		// 捕获异常
		err := recover()
		if err != nil {
			// err: runtime error: integer divide by zero
			fmt.Println("err:", err)
			// 抛出异常
			// panic(err)
		}
	}()
	num1 := 10
	num2 := 0
	div := num1 / num2
	fmt.Printf("div: %v\n", div)
}

func readConf(name string) (err error) {
	if name == "config.init" {
		return nil
	} else {
		return errors.New("Read File error")
	}
}

func test2() {
	err := readConf("config2.init")
	if err != nil {
		// 抛出异常,终止运行
		panic(err) // panic: Read File error
	}
	fmt.Println("test2 test2")
}

func main() {
	test()
	fmt.Println("main...")

	test2()
	fmt.Println("test2 main")
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SoaringW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值