golang学习笔记3:常量与变量

常量

常量使用关键字 const 定义,用于存储不会改变的数据。 存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。 常量的定义格式: const identifier [type] = value ,例如:

1. const Pi = 3.14159

在 Go 语言中,你可以省略类型说明符 [type] ,因为编译器可以根据变量的值来推断其类型。 显式类型定义: const b string = "abc" 隐式类型定义: const b = "abc" 一个没有指定类型的常量被使用时,会根据其使用环境而推断出它所需要具备的类型。换句话说,未定义类型的常量 会在必要时刻根据上下文来获得相关类型。

1. var n int
2. f(n + 5) // 无类型的数字型常量 “5” 它的类型在这里变成了 int

常量的值必须是能够在编译时就能够确定的;你可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在 编译期间就能获得。 正确的做法: const c1 = 2/3 错误的做法: const c2 = getNumber() // 引发构建错误: getNumber() used as value 因为在编译期间自定义函数均属于未知,因此无法用于常量的赋值,但内置函数可以使用,如:len()。 数字型的常量是没有大小和符号的,并且可以使用任何精度而不会导致溢出:

1. const Ln2= 0.693147180559945309417232121458\
2. 176568075500134360255254120680009
3. const Log2E= 1/Ln2 // this is a precise reciprocal
4. const Billion = 1e9 // float constant
5. const hardEight = (1 << 100) >> 97

根据上面的例子我们可以看到,反斜杠 \ 可以在常量表达式中作为多行的连接符使用。与各种类型的数字型变量相比,你无需担心常量之间的类型转换问题,因为它们都是非常理想的数字。 不过需要注意的是,当常量赋值给一个精度过小的数字型变量时,可能会因为无法正确表达常量所代表的数值而导致溢出,这会在编译期间就引发错误。另外,常量也允许使用并行赋值的形式:

1. const beef, two, c = "eat", 2, "veg"
2. const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6
3. const (
4. Monday, Tuesday, Wednesday = 1, 2, 3
5. Thursday, Friday, Saturday = 4, 5, 6
6. )

常量还可以用作枚举:

1. const (
2. Unknown = 0
3. Female = 1
4. Male = 2
5. )

现在,数字 0、1 和 2 分别代表未知性别、女性和男性。这些枚举值可以用于测试某个变量或常量的实际值,比如使用 switch/case 结构.

变量

声明变量的一般形式是使用 var 关键字: var identifier type 。需要注意的是,Go 和许多编程语言不同,它在声明变量时将变量的类型放在变量的名称之后。Go 为什么要选择这么做呢?首先,它是为了避免像 C 语言中那样含糊不清的声明形式,例如: int* a, b; 。在这个例子中,只有 a 是指针而b 不是。如果你想要这两个变量都是指针,则需要将它们分开书写.而在 Go 中,则可以很轻松地将它们都声明为指针类型:

1. var a, b *int

其次,这种语法能够按照从左至右的顺序阅读,使得代码更加容易理解。 示例:

1. var a int
2. var b bool
3. var str string

你也可以改写成这种形式:

1. var (
2. a int
3. b bool
4. str string
5. )

这种因式分解关键字的写法一般用于声明全局变量。 当一个变量被声明之后,系统自动赋予它该类型的零值:int 为 0,float 为 0.0,bool 为 false,string为空字符串,指针为 nil。记住,所有的内存在 Go 中都是经过初始化的。 变量的命名规则遵循骆驼命名法,即首个单词小写,每个新单词的首字母大写,例如: numShips 和 startDate 。 但如果你的全局变量希望能够被外部包所使用,则需要将首个单词的首字母也大写。

一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。如果一个变量在函数体外声明,则被认为是全局变量,可以在整个包甚至外部包(被导出后)使用,不管你声明在哪个源文件里或在哪个源文件里调用该变量。在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。 我们将会学习到像 if 和 for 这些控制结构,而在这些结构中声明的变量的作用域只在相应的代码块内。一般情况下,局部变量的作用域可以通过代码块(用大括号括起来的部分)判断。 尽管变量的标识符必须是唯一的,但你可以在某个代码块的内层代码块中使用相同名称的变量,则此时外部的同名变量将会暂时隐藏(结束内部代码块的执行后隐藏的外部同名变量又会出现,而内部同名变量则被释放),你任何的操作都只会影响内部代码块的局部变量。变量可以编译期间就被赋值,赋值给变量使用运算符等号 = ,当然你也可以在运行时对变量进行赋值操作。 示例:

1. a = 15
2. b = false

一般情况下,当变量a和变量b之间类型相同时,才能进行如 a = b 的赋值。声明与赋值(初始化)语句也可以组合起来。示例:

1. var identifier [type] = value
2. var a int = 15
3. var i = 5
4. var b bool = false
5. var str string = "Go says hello to the world!"

但是 Go 编译器的智商已经高到可以根据变量的值来自动推断其类型,这有点像 Ruby 和 Python 这类动态语言,只不过它们是在运行时进行推断,而 Go 是在编译时就已经完成推断过程。因此,你还可以使用下面的这些形式来声明及初始化变量:

1. var a = 15
2. var b = false
3. var str = "Go says hello to the world!"

或:

1. var (
2. a = 15
3. b = false
4. str = "Go says hello to the world!"
5. numShips = 50
6. city string
7. )

不过自动推断类型并不是任何时候都适用的,当你想要给变量的类型并不是自动推断出的某种类型时,你还是需要显式指定变量的类型,例如:

1. var n int64 = 2

然而, var a 这种语法是不正确的,因为编译器没有任何可以用于自动推断类型的依据。变量的类型也可以在运行时实现自动推断,例如:

1. var (
2. HOME = os.Getenv("HOME")
3. USER = os.Getenv("USER")
4. GOROOT = os.Getenv("GOROOT")
5. )

这种写法主要用于声明包级别的全局变量,当你在函数体内声明局部变量时,应使用简短声明语法 := ,例如:

1. a := 1

下面这个例子展示了如何通过 runtime 包在运行时获取所在的操作系统类型,以及如何通过 os 包中的函数 os.Getenv() 来获取环境变量中的值,并保存到 string 类型的局部变量 path 中。

1. package main
2.
3. import (
4. "fmt"
5. "runtime"
6. "os"
7. )
8.
9. func main() {
10. var goos string = runtime.GOOS
11. fmt.Printf("The operating system is: %s\n", goos)
12. path := os.Getenv("PATH")
13. fmt.Printf("Path is %s\n", path)
14. }

如果你在 Windows 下运行这段代码,则会输出 The operating system is: windows 以及相应的环境变量的值;如果你在 Linux 下运行这段代码,则会输出 The operating system is: linux 以及相应的的环境变量的值。

原文发布于微信公众号 - oldriver编程老司机(bclsj-cn)

原文发表时间:2018-10-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java Web

Java学习笔记(3)—— String类详解

前言 因为没有成功地为IDEA配上反编译工具,所以自己下载了一个XJad工具,背景是白色的,所以忍着强迫症硬是把IDEA的主体也给换成白色了,感觉为了这篇文章...

2795
来自专栏Java架构师历程

精选30道Java笔试题解答

都是一些非常非常基础的题,是我最近参加各大IT公司笔试后靠记忆记下来的,经过整理献给与我一样参加各大IT校园招聘的同学们,纯考Java基础功底,老手们就不用进来...

3354
来自专栏个人随笔

深入理解Java异常处理机制 (笼统篇)

831
来自专栏技术博文

php 使用函数中遇到的坑之----list

1. list 把数组中的值赋给一些变量 <?php $info = array('coffee', 'brown', 'caffeine'); // 列出所有...

2856
来自专栏小樱的经验随笔

【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析

这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try {   //需要被检测的异常代码 } ca...

3969
来自专栏机器学习算法与Python学习

python基础-字符串与编码

转载于:廖雪峰的官方网站-python教程 字符编码 我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。 因为计算机只能处理数字...

48011
来自专栏一“技”之长

Swift讲解专题十——类与结构体 原

        Swift中的类与结构体十分相似,和Objective-C不同的是,Swift中的结构体不仅可以定义属性,也可以像类一样为其定义方法。

912
来自专栏闪电gogogo的专栏

Python入门学习(一)

看完了莫烦Python的视频,对于Python有了一点感觉,接下来打算把小甲鱼的视频啃完,附上学习网址:http://blog.fishc.com/catego...

4018
来自专栏python3

python3--面向对象进阶之内置方法

print执行时,是去内部寻找__str__方法,所以print没有输出不了的数据,因为每一个对象都有__str__方法

851
来自专栏拭心的安卓进阶之路

深入理解 Java 泛型

首先提个问题: Java 泛型的作用是什么?泛型擦除是什么?泛型一般用在什么场景? 如果这个问题你答不上来,那这篇文章可能就对你有些价值。 什么是泛...

5459

扫码关注云+社区

领取腾讯云代金券