一、变量定义

所谓的变量就是一个拥有指定名称类型数据存储位置

//看一个例子
package main
import (
"fmt"
)
func main() {
var x string = "hello world"
fmt.Println(x)
}

变量的定义首先使用var关键字,然后指定变量的名称x,再指定变量的类型string,在本例中,还对变量x进行了赋值,然后在命令行输出该变量。Go这种变量定义的方式和其他的语言有些不同,但是在使用的过程中,你会逐渐喜欢的。当然上面的变量定义方式还可以如下,即先定义变量,再赋值。

    var x string
x = "hello world"

或者是直接赋值,让Go语言推断变量的类型。如下:

var x = "hello world"

当然,上面变量的定义还有一种快捷方式。如果你知道变量的初始值,完全可以像下面这样定义变量,完全让Go来推断语言的类型。这种定义的方式连关键字var都省略掉了。

x := "hello world"

注意:上面这种使用:=方式定义变量的方式只能用在函数内部

package main
import (
"fmt"
)
x:="hello world"
func main() {
y :=
fmt.Println(x)
fmt.Println(y)
}

对于上面的变量定义x是无效的。会导致编译错误:

./test_var_quick.go:: non-declaration statement outside function body

不过我们对上面的例子做下修改,比如这样是可以的。也就是使用var关键字定义的时候,如果给出初始值,就不需要显式指定变量类型。

package main
import (
"fmt"
)
var x = "hello world"
func main() {
y :=
fmt.Println(x)
fmt.Println(y)
}

变量之所以称为变量,就是因为它们的值在程序运行过程中可以发生变化,但是它们的变量类型是无法改变的。因为Go语言是静态语言,并不支持程序运行过程中变量类型发生变化。比如如果你强行将一个字符串值赋值给定义为int的变量,那么会发生编译错误。即使是强制类型转换也是不可以的。强制类型转换只支持同类的变量类型。比如数值类型之间强制转换。

下面我们看几个例子:

package main
import (
"fmt"
)
func main() {
var x string = "hello world"
fmt.Println(x)
x = "i love go language"
fmt.Println(x)
}

本例子演示变量的值在程序运行过程中发生变化,结果输出为

hello world
i love go language

我们尝试不同类型的变量之间转换

package main
import (
"fmt"
)
func main() {
var x string = "hello world"
fmt.Println(x)
x =
fmt.Println(x)
}

在本例子中,如果试图将一个数值赋予字符串变量x,那么会发生错误:

./test_var.go:: cannot use  (type int) as type string in assignment

上面的意思就是无法将整型数值11当作字符串赋予给字符串变量。

但是同类的变量之间是可以强制转换的,如浮点型和整型之间的转换。

package main
import (
"fmt"
)
func main() {
var x float64 = 32.35
fmt.Println(x)
fmt.Println(int(x))
}

输出的结果为

32.35

二、变量命名

上面我们看了一些变量的使用方法,那么定义一个变量名称,有哪些要求呢?
这里我们要注意,Go的变量名称必须以字母或下划线(_)开头,后面可以跟字母,数字,或者下划线(_)。除此之外,Go语言并不关心你如何定义变量。我们通用的做法是定义一个用户友好的变量。假设你需要定义一个狗狗的年龄,那么使用dog_age作为变量名称要好于用x来定义变量。

三、变量作用域

现在我们再来讨论一下变量的作用域。所谓作用域就是可以有效访问变量的区域。比如很简单的,你不可能在一个函数func_a里面访问另一个函数func_b里面定义的局部变量x。所以变量的作用域目前分为两类,一个是全局变量,另一个是局部变量。下面我们看个全局变量的例子:

package main
import (
"fmt"
)
var x string = "hello world"
func main() {
fmt.Println(x)
}

这里变量x定义在main函数之外,但是main函数仍然可以访问x。全局变量的作用域是该包中所有的函数。

package main
import (
"fmt"
)
var x string = "hello world"
func change() {
x = "i love go"
}
func main() {
fmt.Println(x)
change()
fmt.Println(x)
}

在上面的例子用,我们用了change函数改变了x的值。输出结果如下:

hello world
i love go

我们再看一下局部变量的例子。

package main
import (
"fmt"
)
func change() {
x := "i love go"
}
func main() {
fmt.Println(x)
}

该例子中main函数试图访问change函数中定义的局部变量x,结果发生了下面的错误(未定义的变量x):

./test_var.go:: undefined: x

三、常量

Go语言也支持常量定义。所谓常量就是在程序运行过程中保持值不变的变量定义。常量的定义和变量类似,只是用const关键字替换了var关键字,另外常量在定义的时候必须有初始值

package main
import (
"fmt"
)
func main() {
const x string = "hello world"
const y = "hello world"
fmt.Println(x)
fmt.Println(y)
}

这里有一点需要注意,变量定义的类型推断方式:=不能够用来定义常量。因为常量的值是在编译的时候就已经确定的,但是变量的值则是运行的时候才使用的。这样常量定义就无法使用变量类型推断的方式了。

常量的值在运行过程中是无法改变的,强制改变常量的值是无效的。

我们看一个Go包math里面定义的常量Pi,用它来求圆的面积。

package main
import (
"fmt"
"math"
)
func main() {
var radius float64 =
var area = math.Pow(radius, ) * math.Pi
fmt.Println(area)
}

四、多变量或常量定义

Go还提供了一种同时定义多个变量或者常量的快捷方式。

package main
import (
"fmt"
)
func main() {
var (
a int =
b float64 = 32.45
c bool = true
)
const (
Pi float64 = 3.14
True bool = true
)
fmt.Println(a, b, c)
fmt.Println(Pi, True)
}

在定义常量组时,如果不提供初始值,则表示将使用上行的表达式。

package main

import "fmt"

const (
a =
b
c
d
) func main() {
fmt.Println(a)
// b、c、d没有初始化,使用上一行(即a)的值
fmt.Println(b) // 输出1
fmt.Println(c) // 输出1
fmt.Println(d) // 输出1
}

五、iota

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值:

const (
a = iota
b = iota
c = iota
)

第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:

const (
a = iota
b
c
)

iota 用法

实例

package main

import "fmt"

func main() {
const (
a = iota //
b //
c //
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}

以上实例运行结果为:

   ha ha    

再看个有趣的的 iota 实例:

package main

import "fmt"
const (
i=<<iota
j=<<iota
k
l
) func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}

以上实例运行结果为: 

i=
j=
k=
l=

ota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。

简单表述:

i=1

    :左移 0 位,不变仍为 1;

  • j=3:左移 1 位,变为二进制 110, 即 6;
  • k=3:左移 2 位,变为二进制 1100, 即 12;
  • l=3:左移 3 位,变为二进制 11000,即 24。

换个语言学一下 Golang (4)——变量与常量的更多相关文章

  1. 换个语言学一下 Golang (12)——Web基础

    一.web工作方式 我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容.在这个看似简单的用户行为背后,到底隐藏了些什么呢?对于普通的上网过程,系统其实是这样做的 ...

  2. 换个语言学一下 Golang (3)——数据类型

    在 Go 编程语言中,数据类型用于声明函数和变量. 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存. Go 语言按类别有以下几种 ...

  3. 换个语言学一下 Golang (1)

    做技术的总是有些拗.这么多年一直在.net的框框里打转转.直到现在市场上.net工作越来越难找,项目越来越老才发现不做出改变不行了.就从学习Go开始吧. Go语言的特点 简洁.快速.安全 并行.有趣. ...

  4. 换个语言学一下 Golang (11)——使用包和测试

    Go天生就是为了支持良好的项目管理体验而设计的. 包 在软件工程的实践中,我们会遇到很多功能重复的代码,比如去除字符串首尾的空格.高质量软件产品的特点就是它的部分代码是可以重用的,比如你不必每次写个函 ...

  5. 换个语言学一下 Golang (5)——运算符

    运算符用于在程序运行时执行数学或逻辑运算. Go 语言内置的运算符有: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 接下来让我们来详细看看各个运算符的介绍. 算术运算符 下表 ...

  6. 换个语言学一下 Golang (2)——基础语法

    Go 标记 Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号.比如下面的hello world就是由 6 个标记组成: 行分隔符 在 Go 程序中,一行代表一个语句结束.每个语句 ...

  7. 换个语言学一下 Golang(14) ——fmt包

    Print() 函数将参数列表 a 中的各个参数转换为字符串并写入到标准输出中. 非字符串参数之间会添加空格,返回写入的字节数. func Print(a ...interface{}) (n int ...

  8. 换个语言学一下 Golang (13)——Web表单处理

    介绍 表单是我们平常编写Web应用常用的工具,通过表单我们可以方便的让客户端和服务器进 行数据的交互.对于以前开发过Web的用户来说表单都非常熟悉.表单是一个包含表单元素的区域.表单元素是允许用户在表 ...

  9. 换个语言学一下 Golang (10)——并行计算

    如果说Go有什么让人一见钟情的特性,那大概就是并行计算了吧. 做个题目 如果我们列出10以下所有能够被3或者5整除的自然数,那么我们得到的是3,5,6和9.这四个数的和是23.那么请计算1000以下( ...

随机推荐

  1. Unity5.1 新的网络引擎UNET(十五) Networking 引用--中

    孙广东 2015.7.21 本节提供了与网络系统一起使用的组件的具体信息. 3.NetworkClient NetworkClient 是一个 HLAPI 类,管理网络连接到服务器 - - 相应着 U ...

  2. 【打CF,学算法——二星级】CF 520B Two Buttons

    [CF简单介绍] 提交链接:Two Buttons 题面: B. Two Buttons time limit per test 2 seconds memory limit per test 256 ...

  3. Python FAQ2:赋值、浅拷贝、深拷贝的区别?

    在Python编程过程中,经常会遇到对象的拷贝,如果不理解浅拷贝和深拷贝的概念,你的代码就可能出现一些问题.所以,在这里按个人的理解谈谈它们之间的区别. 一.赋值(assignment) 在<P ...

  4. Cisco VPP(1) 简单介绍

    一.简单介绍 VPP全称Vector Packet Processing.是Cisco2002年开发的商用代码. 2016年2月11号,Linux基金会创建FD.io项目.Cisco将VPP代码的开源 ...

  5. Solr基础教程之solrconfig.xml(三)

    前面介绍过schema.xml的一些配置信息,本章介绍solrconfig.xml的配置,以及怎样安装smartcn分词器和IK分词器,并介绍主要的查询语法. 1. solr配置solrconfig. ...

  6. C++ 訪问控制权限图解

    基类訪问权限 类继承方式 子类訪问权限           public   public   protected public protected   private   No Access   p ...

  7. oc69--NSMutableString

    // main.m // NSMutableString基本概念,NSString是不可变字符串,NSMutableString是可变字符串.NSMutableString继承NSString,所以N ...

  8. poj3463 Sightseeing——次短路计数

    题目:http://poj.org/problem?id=3463 次短路计数问题,在更新最短路的同时分类成比最短路短.长于最短路而短于次短路.比次短路长三种情况讨论一下,更新次短路: 然而其实不必被 ...

  9. java 锁机制(synchronized 与 Lock)

    在java中,解决同步问题,很多时候都会使用到synchronized和Lock,这两者都是在多线程并发时候常使用的锁机制. synchronized是java中的一个关键字,也就是说是java内置的 ...

  10. [ SHOI 2014 ] 概率充电器

    \(\\\) \(Description\) 一个含\(N\)个元器件的树形结构充电器,第\(i\)个元器件有\(P_i\)的概率直接从外部被充电,连接\(i,j\)的边有\(P_{i,j}\)的概率 ...