重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
GO是编译性语言,所以函数的顺序是无关紧要的,为了方便阅读,建议入口函数 main 写在最前面,其余函数按照功能需要进行排列
为鹤山等地区用户提供了全套网页设计制作服务,及鹤山网站建设行业解决方案。主营业务为网站设计、成都做网站、鹤山网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
GO的函数 不支持嵌套,重载和默认参数
GO的函数 支持 无需声明变量,可变长度,多返回值,匿名,闭包等
GO的函数用 func 来声明,且左大括号 { 不能另起一行
一个简单的示例:
输出为:
参数:可以传0个或多个值来供自己用
返回:通过用 return 来进行返回
输出为:
上面就是一个典型的多参数传递与多返回值
对例子的说明:
按值传递:是对某个变量进行复制,不能更改原变量的值
引用传递:相当于按指针传递,可以同时改变原来的值,并且消耗的内存会更少,只有4或8个字节的消耗
在上例中,返回值 (d int, e int, f int) { 是进行了命名,如果不想命名可以写成 (int,int,int){ ,返回的结果都是一样的,但要注意:
当返回了多个值,我们某些变量不想要,或实际用不到,我们可以使用 _ 来补位,例如上例的返回我们可以写成 d,_,f := test(a,b,c) ,我们不想要中间的返回值,可以以这种形式来舍弃掉
在参数后面以 变量 ... type 这种形式的,我们就要以判断出这是一个可变长度的参数
输出为:
在上例中, strs ...string 中, strs 的实际值是b,c,d,e,这就是一个最简单的传递可变长度的参数的例子,更多一些演变的形式,都非常类似
在GO中 defer 关键字非常重要,相当于面相对像中的析构函数,也就是在某个函数执行完成后,GO会自动这个;
如果在多层循环中函数里,都定义了 defer ,那么它的执行顺序是先进后出;
当某个函数出现严重错误时, defer 也会被调用
输出为
这是一个最简单的测试了,当然还有更复杂的调用,比如调试程序时,判断是哪个函数出了问题,完全可以根据 defer 打印出来的内容来进行判断,非常快速,这种留给你们去实现
一个函数在函数体内自己调用自己我们称之为递归函数,在做递归调用时,经常会将内存给占满,这是非常要注意的,常用的比如,快速排序就是用的递归调用
本篇重点介绍了GO函数(func)的声明与使用,下一篇将介绍GO的结构 struct
一般来说,我们不会直接使用ASCII码来处理,因为这样不够直观。比如你说的判定输入是否是字母,是否是数字,那么有个比较直观的方法来处理。如果你看过ASCII码表,那么你就知道字数和字母在ASCII码表中都是连续的,所以这个就比较好解决了。
判定字符ch是否是数字:
if(ch='0' ch='9')
判定字符ch是否是字母:
if(ch='a' ch='z' || ch='A' ch='Z')
当然,有已经定义好的库函数用来判定是否数字和字母,不要加加载头文件ctype.h
判定字符ch是否是数字:
if(isalnum(ch));
判定字符ch是否是字母:
if(isalpha(ch));
这两个函数都是判定成立,结果是true也就是1,判定不成立,结果是false,也就是0.
import (
"fmt"
"reflect"
)
func reflecType(x interface{}){
v := reflect.TypeOf(x)
fmt.Println("type:%v\n", v)
fmt.Println("type name:%v , rtpe kind:%v \n", v.getName(), v.getType())
}
type Cat struct{}
//通过反射设置变量的值
func reflectSetValue1(x interface{}){
v := reflect.ValueOf(x)
if v.Kind() == reflect.Int64{
v.SetInt(200) //修改的是副本, reflect 包会引发panic
}
}
//通过反射设置变量的值
func reflectSetValue2(x interface{}){
v := reflect.ValueOf(x)
//反射中使用Elem()获取指针对应的值
if v.Elem().Kind() == reflect.Int64{
v.Elem().SetInt(200)
}
}
func main(){
var a float32 = 3.14
reflectType(a) //type name:float32 type kind:float32
var b int64 = 100
reflectType(b) // type name :int64 type kind :int64
var c = Cat{}
reflectType(c) // type name :Cat type kind :struct
reflectSetValue1(b)
fmt.Println(b) //依然为100
reflectSetValue2(b)
}
1、反射可以在运行时 动态获取变量的各种信息 ,比如变量的类型、类别;
2、如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法);
3、通过反射,可以修改 变量的值 ,可以调用关联的方法;
4、使用反射,需要import " reflect ".
5、示意图:
1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。
例如以下这种桥接模式:
示例第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数。
1、reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型。
2、reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。
3、变量、interface{}和reflect.Value是可以互相转换的,这点在实际开发中,会经常使用到。
1、reflect.Value.Kind,获取变量的 类别(Kind) ,返回的是一个 常量 。在go语言文档中:
示例如下所示:
输出如下:
Kind的范畴要比Type大。比如有Student和Consumer两个结构体,他们的 Type 分别是 Student 和 Consumer ,但是它们的 Kind 都是 struct 。
2、Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的。
3、通过反射可以在让 变量 在 interface{} 和 Reflect.Value 之间相互转换,这点在前面画过示意图。
4、使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么久应该使用reflect.Value(x).Int(),而不能使用其它的,否则报panic。
如果是x是float类型的话,也是要用reflect.Value(x).Float()。但是如果是struct类型的话,由于type并不确定,所以没有相应的方法,只能 断言。
5、通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法。
输出num=20,即成功使用反射来修改传进来变量的值。
6、reflect.Value.Elem()应该如何理解?