山东网站建设都有那些,个人网站转企业,用照片做的ppt模板下载网站好,上海搬家公司有哪些2、程序结构
2.1 命名
一个名字必须以一个字母或下划线开头#xff0c;后面可以跟任意数量的字母、数字或下划线。 大写字母和小写字母是不同的。 GO语言有25个关键字#xff0c;关键字不能用于自定义名字。 还有大约30多个预定义名字#xff0c;对应内建的常量、类型和函…2、程序结构
2.1 命名
一个名字必须以一个字母或下划线开头后面可以跟任意数量的字母、数字或下划线。 大写字母和小写字母是不同的。 GO语言有25个关键字关键字不能用于自定义名字。 还有大约30多个预定义名字对应内建的常量、类型和函数内部预定义名字可以在定义中重新使用他们但也要避免过度而引起语义混乱。 名字是大写字母开头必须是在函数外部定义的包级名字包级函数名本身也是包级名字那么它将是导出的可以被外部的包访问。 包本身的名字一般都是用小写字母。 名字的长度没有逻辑限制但尽量使用短小的名字。 驼峰式命名
2.2 声明
声明语句定义了程序的各种实体对象以及部分或全部的属性。 var变量、const常量、type类型、func函数实体对象 一个go语言编写的程序对应一个或多个以.go为文件后缀名的源文件中。每个源文件以包的声明语句开始说明该源文件是属于哪个包包声明语句之后是import语句导入依赖的其他包然后是包一级的类型、变量、常量、函数的声明语句包一级的各种类型的声明语句的顺序无光紧要函数内部的名字则必须先声明之后才能使用
package mainimport fmtconst boilingF212.0func main(){var fboilingFvar c(f-32)*5/9fmt.Printf(boiling point%g F or %g C\n,f,c)
}在包一级声明语句的名字可在整个包对应的每个源文件中访问而不仅仅在其声明语句所在的源文件中访问局部声明的名字就只能在函数内部很小的范围被访问。
package mainimport fmtfunc main(){const freezingF,boilingF32.0 212.0fmt.Printf(%g F or %g C\n,freezingF,fToC(freezingF))fmt.Printf(%g F or %g C\n,boilingF,fToC(boilingF))
}func fToC(f float64) float64{return (f-32)*5/9
} 2.3 变量
var 变量名字 类型表达式零值初始化机制
var s string
fmt.Println(s)//一组变量
var i,j,k int
var b,f,strue,2.3,four在包级别声明的变量会在main入口函数执行前完成初始化局部变量将在声明语句被执行到的时候完成初始化。 一组变量也可以通过调用一个函数由函数返回的多个返回值初始化
var f,erros.Open(name)2.3.1 简短变量声明
变量的类型根据表达式来自动推导简短变量声明被广泛用于大部分的局部变量的声明和初始化。
变量名表达式i:100
j,k:0,1f,err:os.Open(name)简短变量声明左边的变量可能并不是全部都是刚刚声明过。如果有一些已经在相同的词法域声明过了那么简短变量声明语句对这些已经声明过的变量就只有赋值行为了。
in,err:os.Open(infile)
out,err:os.Create(outfile)简短变量语句中必须至少要声明一个新的变量。 简短变量声明语句只有对已经在同级词法域声明过的变量才和赋值操作语句等价如果变量是在外部词法域声明的那么简短变量声明语句将会在当前词法域重新声明一个新的变量。
2.3.2 指针
指针的值是另一个变量的地址。 x//取变量x的内存地址
*p//读取指针指向的变量的值x:1
p:x
fmt.Println(*p)//1
*p2
fmt.Println(x)//2var x,y int
fmt.Println(xx,xy,xnil)//true false false返回函数中局部变量的地址也是安全的。
var pf()func f() *int{v:1return v
}每次调用f函数都将返回不同的结果
fmt.Println(f()f())//false指针作为参数调用函数可以在函数中通过该指针来更新变量的值。
func incr(p *int) int{*p//增加p指向的变量的值并不改变p指针return *p
}v:1
incr(v)//2
fmt.Println(incr(v))//3*p是变量v的别名 指针是实现标准库flag包的关键技术它使用命令行参数来设置对应变量的值而这些对应命令行标志参数的变量可能会零散分布在整个程序中。
2.3.3 new函数
创建变量 new(T)将创建一个T类型的匿名变量初始化为T类型的零值然后返回变量地址返回的指针类型为*T
p:new(int)//p*int 类型指向匿名的int变量
fmt.Println(*p)//0
*p2
fmt.Println(*p)//2用new创建变量和普通变量声明语句方式创建变量没有什么区别除了不需要声明一个临时变量的名字。 在表达式中使用new(T) 下面的两个newInt函数有着相同的行为
func newInt() *int{return new(int)
}func newInt() *int{var dummy intreturn dummy
}每次调用new函数都是返回一个新的变量地址下面两个地址都是不同的
p:new(int)
q:new(int)
fmt.Println(pq)//falsenew只是一个预定义函数它并不是一个关键字我们可以将new名字重新定义别的类型
func delta(old,new int) int {return new-old}由于new被定义为int类型的变量名因此delta函数内部是无法使用内置的new函数的。
2.3.4 变量的生命周期
包一级声明的变量生命周期和整个程序的运行周期是一致的。 局部变量的声明周期则是动态的每次从创建一个新变量的声明语句开始直到该变量不再被引用为止然后变量的存储空间可能被回收。函数的参数变量和返回值变量都是局部变量。它们在函数每次被调用的时候创建。
函数的右小括弧也可以另起一行缩进同时为了防止编译器在行尾自动插入分号而导致编译错误可以在末尾的参数变量后面显式插入逗号。
img.SetColorIndex(sizeint(x*size0.5),sizeint(y*size0.5),blackIndex,
)Go语言的自动垃圾收集器【不需要显式地分配和释放内存】是如何知道一个变量是何时可以被回收的基本实现思路从每个包级的变量和每个当前运行函数的每个当前运行函数的每一个局部变量开始通过指针或引用的访问路径遍历是否可以找到该变量。如果不存在这样的访问路径那么说明该变量是不可达的也就是说它是否存在并不影响程序后续的计算结果。 一个变量的有效周期只取决于是否可达因此一个循环迭代内部的局部变量的生命周期可能超出其局部作用域。局部变量可能在函数返回之后依然存在。
编译器会自动选择在栈上还是在堆上分配局部变量的存储空间这个选择并不是由var还是new声明变量的方式决定。
var global *intfunc f(){var x intx1globalx
}func g(){y:new(int)*y1
}f函数的x变量必须在堆上分配它在函数退出后依然可以通过包一级的global变量找到虽然它是在函数内部定义的x局部变量从函数f中逃逸了。
当g函数返回时变量*y将是不可达的可以马上被回收的编译器可以选择在栈上分配存储空间。
2.4 赋值
x1
*ptrue
person.namebob
count[x]count[x]*scale
count[x]*scale递增和–递减语句是语句而不是表达式xi是错误的
v:1
v
v--2.4.1 元组赋值
同时更新多个变量的值
x,yy,x
a[i],a[j]a[j],a[i]//计算两个整数值的最大公约数
func gcd(x,y int) int{for y!0{x,yy,x%y}return x
}//计算斐波纳契数列的第n个数func fib(n int)int{x,y:0,1for i:0;in;i{x,yy,xy}return x
}元组赋值可以使一系列琐碎赋值更加紧凑特别是在for循环的初始化部分
i,j,k2,3,5调用一个有多个返回值的函数
f,erros.Open(foo.txt)如果map查找、类型断言或通信接收出现在赋值语句的右边它们都可能会产生两个结果有一个额外的布尔结果表示操作是否成功
v,okmap[key]
v,okx.(T)
v,ok-chmap查找、类型断言或通道接收出现在赋值语句的右边并不一定是产生两个结果也可能只产生一个结果。map查找失败时返回零值类型断言失败时会发送运行panic异常通道接收失败时会返回零值阻塞不算是失败。 我们可以用_来丢弃不需要的值。
_,errio.Cpoy(dst,src)//丢弃字节数
_,okX.(T)//只检测类型忽略具体值2.4.2 可赋值性
隐式赋值行为函数调用会隐式地将调用参数的值赋值给函数的参数变量一个返回语句会隐式地将返回操作的值赋值给结果变量一个复合类型的字面量也会产生赋值行为。 隐式地对slice的每个元素进行赋值操作
medals:[]string{gold,silver,bronze}类型必须完全匹配nil可以赋值给任何指针或引用类型的变量。避免不必要的显式的类型转换。
2.5 类型
类型声明语句创建一个新的类型名称
type 类型名字 底层类型类型声明语句一般出现在包一级如果新创建的类型名字的首字符大写则在外部包也可以使用 我们将不同温度单位分别定义为不同的类型
package tempconvimport fmttype Celsius float64 //摄氏温度
type Fahrenheit float64//华氏温度const (AbsoluteZeroC Celsius-273.15//绝对零度FreezingC Celsius0//结冰点零度BoilingC Celsius100//沸水温度
)func CToF(c Celsius) Fahrenheit {return Fahrenheit(c*9/532)}func FToC(f Fahrenheit) Celsius {return Celsius((f-32)*5/9)}对于每一个类型T都有一个对应的类型转换操作T(x)将x转为T类型。
命名类型还可以为该类型的值定义新的行为。 声明Celsius类型的一个名为String方法。
func (c Celsius) String() string {return fmt.Sprintf(%g Cc)}2.6 包和文件
包为了支持模块化、封装、单独编译和代码重用。
2.6.1 导入包
每个包都有一个全局唯一的导入路径。 包名在包的声明处指定。 import 包名 如果导入了一个包但是又没有使用该包将当作一个编译错误处理。 goimports工具根据需要自动添加或删除导入的包。
2.6.2 包的初始化
包的初始化首先是解决包级变量的依赖顺序然后按照包级变量声明出现的顺序依次初始化。
var abc //3
var bf() //2
var c1 //1
func f() int {return c1}如果包中含有多个.go源文件它们将按照发给编译器的顺序进行初始化
初始化表达式初始化特殊的init初始化函数来简化初始化工作 每个包在解决依赖的前提下以导入声明的顺序初始化每个包只会被初始化一次。 匿名函数
2.7 作用域
声明语句的作用域是指源代码中可以有效使用这个名字的范围。 不要将作用域和生命周期混淆。生命周期是程序运行时变量存在的有效时间段在此时间区域内他可以被程序的其他部分引用是一个运行时的概念。 句法块 词法块 语法块 要特别注意短变量声明语句的作用域范围。