《Go程序设计语言》2 程序结构

声明

  • 声明是给一个程序实体命名
  • 有4个主要的声明
    • var:变量
    • const:常量
    • type:类型
    • func:函数

程序员以多个以.go为后缀的文件里。

  • 每一个文件以package开头,表明文件属于哪个包
  • 后面是import声明
  • 然后是包级别 的四大声明

变量

var name type = expression

类型和表达式可以省略其一

  • 省略类型:则自动根据初始化表达式推断类型
  • 省略表达式:自动初始化为该类型对应的0值
    • 数字0,布尔false,字符串空串,接口和医用类型是nil,符合类型是所有成员零值的集合

可以进行列表初始化

var b,f,s = true,2.3,"four"

可以通过调用返回多个值的函数对变量列表进行初始化

var f,err = os.Open(name)

一般在面对返回多个值的函数时,若某返回值不需要,一般使用_给它占位

var f, _ = os.Open(name)

短变量声明

使用 name:=expression,直接声明变量,其类型是靠推断得来

指针

指针和C的指针是没啥区别的,不过令人震惊的是竟然可以返回函数中局部变量的指针

func f() *int {
	v := 1
	return &v
}

new函数

就是c++的new函数,返回某类型的地址

p := new(int)

变量的生命周期

  • 包级别变量在整个程序执行期间持续存在
  • 局部变量一致生存到其变得 不可访问

逃逸

令人震惊的是,在堆还是在栈上创建变量与是否使用new无关

比如下面的

var global *int
func f() {
	var x int
	x = 1
	global = &x
}

这里的x在函数调用结束后,其仍能通过global访问到,所以其生命周期不仅仅局限于函数调用期间,我们说这是x逃逸了f,此时x的变量存储在堆上

func g() {
	 y := new(int)
	 *y = 1
}

该局部变量y在函数调用后就不可达了,所以y的生命周期只在每次调用期间。其被放在栈上

GO的垃圾回收机制保证了其正确性

赋值

使用一个=代表赋值

多重赋值

在更新左侧变量前,右侧表达式是被同时推演的。

所以可以有令人震惊的下一句

x, y = y, x

即可互换两个变量的值

隐式赋值

  • 函数参数
  • return
  • 复合类型
  • map和通道

可赋值性

可赋值性决定了赋值语句的合法不合法

  • 类型必须精确匹配
  • nil可以赋值给任意接口变量或引用类型

类型声明

type name underlying-type

将某个自己定的名字绑定到某底层类型,就像C里面#define LL long long int ;

通常类型的声明出现在包级别

type Celsius float64
type Fahenheit float64

注意虽然此时虽然两者的底层类型相同,但仍不满足可赋值性的条件

我们可以通过下面的神奇操作将一个函数“关联”到类型上,(就好像是面向对象中的成员函数一样)

func (c Celsius) String() string {
	return fmt.Sprinf("%g°C",c)
}

通过在声明后紧跟一个(c Celsius)使得我们可以这样调用函数c.Strng()

包和文件

一个GO语言项目的样式可能是下面

myproject/
   |- main.go
   |- config/
   |    |- config.go
   |- controllers/
   |    |- user_controller.go
   |- models/
   |    |- user.go
   |- services/
   |    |- user_service.go
   |- views/
   |    |- user_view.go
   |- utils/
        |- utils.go

一个包的源源码保存在一个或多个以.go结尾的文件中,一个包的所有文件保存在以包名为名字的文件夹内

main是我们的入口,他的前列的声明可能看起来是这样的

package main

import (
    "myproject/config"
    "myproject/controllers"
)

定义 package

o语言中每个文件的第一行都必须是package声明,它定义了当前文件所属的package。一个package可以由多个文件组成,但是它们必须属于同一个目录。

包级别的变量和函数

  • package级别的变量和函数可以被同一个package中的所有文件访问。
  • 这些变量和函数可以通过使用package名前缀来访问

导入package

每一个包通过称为导入路径的唯一字符串来标识,就像import ("myproject/config"),注意包名=文件夹名

导入后我们可以使用别的包中的变量和函数

可导出的变量和函数

这里和C++面向对象继承的东西很类似

  • 以大写字母开头的函数和包级别变量(相当于父类的public),在包导入后(类似于继承),可以通过包名 .名字使用(可以被子类调用)
  • 其它的(相当于父类的private),就算被导入(类似于继承),也只能同过原来包的可到出的方法进行访问(只能通过父类的共有方法访问)

包的初始化

有点像类的构造函数,当程序开始运行时,按照包的导入顺序开始初始化(类比面向对象构造函数的调用顺序)

  • 有初始化表达式的包级变量先被初始化,按照声明的顺序进行
  • 使用任意数量的func init() {} 进行其它的初始化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值