Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性
一、前言
当我们项目较为简单时,我们在src目录下新建一个该项目目录,里面存放源码文件即可,见下图:
当我们一个项目较为复杂时,我们可以在src目录下新建一个该项目目录,在针对该项目不同模块创建不同目录,比如说logic(逻辑)、views(图片渲染)、data(数据库)等等。
二、第一个Go程序hello world
2.1 代码
package main import (
"fmt"
) //程序执行的入口函数
func main() {
fmt.Print("hello world")
fmt.Printf("hello world,%d\n ", 100)
fmt.Println("hello world")
}
2.2 相关解释
♦ go语言中所有的代码(源码)不能够单独存在,必须隶属于一个包。例:第一行package main表示hello.go属于main包的。
♦ 如果是为了将代码编译成一个可执行程序,那么package必须是main;如果是为了将代码编译成库,那么package则没有限制。
♦ fmt 是go的一个系统库,所以如果我们要使用这个系统库就需要将fmp这个包导入,才能引用这个包中的函数和方法,而println就是fmt库中的一个函数,fmt.println()可以打印输出。
♦ go语言中,很多东西都是强制性的,需要去慢慢习惯。对于python等解释性语言,在函数中随便写一些语句,就可以执行了,但go不行,go语言中,程序执行的入口就是main函数(当编译完后,就是一个可执行程序,可双击执行,可执行程序的入口就是执行main函数中的内容)。
♦ 注意:go语言中函数的花括号“{”一定要放在函数名所在行的行末。此处为强制性要求。
♦ fmt库中,print表示打印内容,printf表示格式化输出(%d表示占位符,指的是整型int,\n表示换行),println表示换行输出。
2.3 编译并执行
1、在当前终端中编译该程序实例
无任何输出是好事,表示程序无问题。
2、我们可以发现在当前目录已经出现了一个可执行程序
hello.exe就是编译后生成的可执行程序文件。
3、我们可以在当前终端目录下直接执行该可执行程序(windows环境也可以直接去所在目录双击执行即可)。
2.4 其他案例
上述hello world当我们在windows环境双击执行时,会发现打开后就退出了,这是正常的,程序执行完自然就退出了。此处我们我来写一个等待用户输入之后,在退出的小例子。
注意:print是打印(输出),而此处我们是要输入,用到scan,因为是输入,所以要定义一个变量来接收输入的这个值。
package main import (
"fmt"
) //程序执行的入口函数
func main() {
fmt.Print("hello world")
fmt.Printf("hello world,%d\n ", 100)
fmt.Println("hello world") var a int
fmt.Scan(&a) //等待用户输入然后退出
}
执行后的结果:
三、go基本命令介绍
基本命令
♦ go run 快速执行go文件,就像执行脚本一样(先编译(编译好文件放在一个临时文件下)在执行。注意:需指定要编译的源码文件)
♦ go build 编译程序,生成二进制可执行文件(将当前目录下所有源码编译)
♦ go install 安装可执行文件到bin目录(编译并安装,针对当前目录下所有源码)
♦ go test 执行单元测试或压力测试
♦ go env 显示go相关的环境变量
♦ go fmt 格式化源代码(当我们从网络上找了些源码格式混乱时,需要针对该源码文件打开终端执行gofmt –w .)
一般来说我们的ide在我们保存时就已经将代码格式化了。
补充:
1、GOPATH下全路径编译
当处于GOPATH路径下进行编译时,要写源代码所在全路径时,不用写src,因为go中已经固定死了(默认就是往src目录下去找)。情况如下图所示(图中GOPATH为d:\project):
go intsall同go build一模一样。
四、go的程序结构
4.1 关于注释
单行注释://
多行注释:/* */
4.2
程序结构
♦ 一个项目(目录)下所有代码文件应只属于一个包(多个会报错),也就是说一个目录下写的是一个大的功能,这些个功能只能归属于一个包。
♦ go源码按package进行组织,并且package要放到非注释的第一行
♦ 一个程序(代码)只有一个main函数
♦ main函数是程序的执行入口
♦ 代码是可执行程序,那么package必须是main,包是main是定死的,函数也必须是main也是定死的,否则就会报错(因为package已经声明了是main,那就表明这是可执行程序,如果此时函数不是main那就会报错。)package(包) main 和func(函数)main是一一对应的。
可参考下图更好理解main。
4.3 包的概念
1. 和python一样,把相同功能的代码放到一个目录,称之为包
2. 包可以被其他包引用
3. main包是用来生成可执行文件,每个程序只有一个main包
4. 包的主要用途是提高代码的可复用性
五、标识符和关键字
1、标识符是用来表示Go中的变量名或者函数名,以字母或_开头。后面跟着字母、 _或数字
如:_ab28 和ab_28就是合法的,88ab就是不合法的。
2、关键字是Go语言预先定义好的,有特殊含义的标识符。
六、变量和常量
6.1 变量
语法:var identifier type
var 变量名 变量类型
变量名 = 值
注意:
1、go语言中定义的变量必须被用到,否则会报错(但是也有解决办法:如果定义的变量d未被用到,我们可以使用 _ = d 来忽略变量d)
2、同时定义变量和赋值可以一步完成。
3、type可以省略不写,系统会自动根据后面给定的值进行判别
4、Go语言中变量命名推荐驼峰语法
例1:
var a int
var b string
var c bool
var d int = 8
var e string = "hello"
我们会发现当定义多个变量会显得很繁琐,每一个都必须写var,其实可以不用每个都写,具体见例2.
例2:
var (
a int //0 不赋值默认为0
b string //“” 不赋值默认为空
c bool //false 不赋值默认为false
d int = 8 // 8
e string = "hello" //hello
)
例3打印变量小案例:
将上述定义的变量打印出来
package main import (
"fmt"
) var (
a int //0 不赋值默认为0
b string //“” 不赋值默认为空
c bool //false 不赋值默认为false
d int = 8 // 8
e string = "hello" //hello
) func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
fmt.Println(e)
}
执行结果:
补充:
var a int =10 可以简写为 a :=10(:=表示声明并初始化变量)
6.2 常量
常量使用const 修饰,代表永远是只读的,不能修改。
语法:
const identifier [type] = value,其中type可以省略。
实例6-1 例1:常规写法
const b string = "hello world"
const b = "hello world"
const Pi = 3.1414926
const a = 9/3
实例6-2 例2:优雅写法
const(
a = 1
b = 2
c = 3
)
实例6-3 例3:专业写法1
如果我们上述定义的的常量a、b、c是有序的,我们可以使用下面的专业写法
const (
a = iota
b = iota
c = iota
)
# iota表示自动从0开始,第一行为0(以行为单位,和行数绑定,第一行为0,第二行为1,第三行为2),往后递增。a=0,b=1,c=2
简写为如下:一般用简写
const (
a = iota
b
c
)
注意:iota是与行数相绑定的,与行号相关,下面这个例子来加深印象
package main import (
"fmt"
) const (
a = 5
b = iota
c
d = 3
e
f
g = iota
) func main() {
fmt.Printf("a=%d b=%d c=%d d=%d e=%d f=%d g=%d", a, b, c, d, e, f, g)
}
执行结果:
解释:
第一行a=5
第二行b=iota,因为是第二行了了所以b=1(第一行iota=0,第二行iota=1)
第三行c,因为第二行是b = iota,所以相邻c = iota,所以c=2
第四行d=3
第五行e相邻d=3,所以e=3
第六行f也是等于3
第七行g=iota,因为是第7行了所以g=6(注意第一行是以0开始而不是1)
实例6-4 例4 专业写法2
const(
a = 1 << iota
b
c
)
#iota可以方便的迭代一个值从0以步长1递增,0,1,2,3,4,5…
结果:a=1,b=2,c=4
七、数据类型和操作符
7.1 布尔类型
a. var b bool 和 var b bool = true 和 var b = false
b. 操作符 == 和 !=
c. 取反操作符: !b
d. && 和 || 操作符
e. 格式化输出占位符: %t
实例7-1
package main import (
"fmt"
) func main() {
var b = false
var (
c = true
d bool = false
) _ = d //因为此程序d变量没有用到,此处我们将d变量赋值给_,_就相当于忽略的意思 if !b {
fmt.Printf("b is false\n")
}
if !b && c {
fmt.Printf("result is true\n")
} /*
if b || c == true { }
*/
if b || c {
fmt.Printf("or operation\n")
}
}
执行结果如下:
7.2 整数和浮点数类型
a. 符号:int8(1字节)、int16(2字节)、int32(4字节)、int64(8字节)
b. 无符号:uint8、uint16、uint32、uint64
c. int和uint和操作系统平台相关(比如说:64位系统占8字节,32位系统占4字节,所以如果跨平台的话最好采用a和b带数字下标的形式,这样可扩展性比较好)
d. float32(4字节)和float64(8字节)浮点类型
e. 所有整数初始化为0,所有浮点数初始化为0.0,布尔类型初始化为false
f. Go是强类型语言,不同类型相加以及赋值是不允许的(比如说:定义为int,永远是int类型。int和int32是不同类型,不能相加也不能互相赋值)
g. 那怎么样才能实现,不同类型相加呢?
比如:int和int32类型想要相加,那必须得做一个强制转换,转换成相同类型数据才能相加或者赋值
h. 输出占位符:整数%d, %x十六进制, %f浮点数
补充:
1字节===8个二进制位===11111111 相当于最大值256(2^8) 如果有符号的话最大值是127
实例7-2
package main import (
"fmt"
) func main() {
var a int = 10
var b int32 = 10
var c int c = a + int(b) var d int = int(b)
fmt.Print(a, b, c, d)
fmt.Println() //不输出任何值表示换行
fmt.Printf("%x\n", c) //输出16进制c
}
执行结果:
7.3 字符串类型
a. var str string
b. var str string = “hello world”
c. 字符串输出占位符%s
d. 万能输出占位符: %v (当不确定数据具体是什么类型时,用什么占位符时,系统自动帮我们进行转换。)
package main import (
"fmt"
) func main() {
var b string = "hello"
var c = "hello" fmt.Printf("b=%v and c=%s\n", b, c)
}
执行结果:
7.4 字符串的两种表示方式
a. 双引号, “”,可以包含控制字符
b. 反引号, ``,所有字符都是原样输出
c.字符必须用单引号括起来,不能用双引号,字符串用双引号。
实例7-3
package main import (
"fmt"
) func main() {
var str = "hello world\n\n" // \n是控制字符换行,""的话可以包含控制字符,输出换行
var str2 = `hello \n \n \n` // ``所有字符都会原样输出 fmt.Println("str=", str)
fmt.Println("str2=", str2)
}
输出结果:
实例7-4
package main import (
"fmt"
) func test_str1() {
var b string = "hello\n\n\n"
var c = "hello" fmt.Printf("b=%v and c = %s\n", b, c)
}
func test_str2() {
var b string = `
床前明月光\n,
疑是地上霜。
举头望明月,
低头思故乡。
` fmt.Printf("b %s\n", b)
}
func test_char() {
var c rune //rune用来表示一个utf8的字符
c = 20320
var d byte //byte表示一个字节
d = 'd'
//c = '你' //'你'的utf8编码是20320,所以下面代码输出‘你’
var e rune = '喊'
fmt.Printf("c=%c d=%c e=%c\n", c, d, e) // %c输出字符
}
func main() {
test_str1()
test_str2()
test_char()
}
输出结果:
补充:go语言中支持以下格式输出。
目前printf支持以下格式的输出,例如:
printf("%c",a);输出单个字符。
printf("%d",a);输出十进制整数。
printf("%f",a);输出十进制浮点数.
printf("%o",a);输出八进制数。
printf("%s",a);输出字符串。
printf("%u",a);输出无符号十进制数。
printf("%x",a);输出十六进制数。
7.5 操作符
a. 逻辑操作符, == 、 != 、 <、 <=、 >=
b. 算数操作符, +、 -、 *、 /、 %
八、 Go程序的基本结构延伸
1. 任何一个代码文件隶属于一个包
2. import 关键字,引用其他包:
import "fmt"
import("os")
通常习惯写成:
import (
"fmt"
"os"
)
3. 开发可执行程序, package main,
并且有且只有一个main入口函数。
4. 包中函数调用:
a. 同一个包中函数,直接用函数名调用
b. 不同包中函数,通过包名+点+函数名进行调用
5. 包访问控制规则:
a. 大写意味着这个函数/变量是可导出
b. 小写意味着这个函数/变量是私有的,包外部不能访问
实例8-1
目录结构:
calc:做第三方库
calc.go
package calc import (
"fmt"
) func Add(a int, b int) int {
var c = a + b
fmt.Printf("add result:%d\n", c)
return c
}
编译安装为静态库:
编译后的静态库:(main包为可执行包,编译后的文件为.go后缀二进制文件,main之外的包,编译后存在pkg下,后缀为.a文件)
可执行程序main.go
package main import (
"day1/calc"
"fmt"
) func main() {
var c int
c = calc.Add(2, 3)
fmt.Printf("c=%d\n", c)
}
执行结果:
九、 Go语言特性
1. 垃圾回收
a. 内存自动回收,再也不需要开发人员管理内存
b. 开发人员专注业务实现,降低了心智负担
c. 只需要new分配内存,不需要释放
2. 天然并发
a. 从语言层面支持并发,非常简单(用户态实现,避免了用户态和内核态的频繁切换)
b. goroutine(协程),轻量级线程,创建成千上万个goroute成为可能(go成千上万个goroutine在用户态跑时,可能操作系统(内核)只有几千个线程再跑,java有多少个线程在用户态跑,就有多少个线程在内核态跑)
c. 基于CSP(Communicating Sequential Process)模型实现(其实就是goroutine+channel,线程之间通信借助管道)
实例9-1
原有程序案例是:
calc.go
package calc import (
"fmt"
) func Add(a int, b int) int {
var c = a + b
fmt.Printf("add result:%d\n", c)
return c
}
main.go 示例1
package main import (
"day1/calc"
"fmt"
) func main() {
var c int
calc.Add(2, 3)
fmt.Printf("c=%d\n", c)
}
目前是同步执行的,如果想要异步执行,只需要如下(标红)操作即可,那样就变成多线程的了,代码示例如下:
main.go
示例2:
package main import (
"day1/calc"
"fmt"
) func main() {
var c int
go calc.Add(2, 3)
fmt.Printf("c=%d\n", c)
}
接下来演示效果:
如果是单线程跑,代码示例如示例1:执行结果如下:
解释:单线程跑的话,是同步的,先调函数打印出加法计算结果,然后在打出c的值。单线程是顺序输出,固定输出的。
如果是多线程跑,代码示例如示例2:实行结果如下:
解释:
go calc.Add(2, 3) 相当于起了一个线程再跑,fmt.Printf("c=%d\n", c),是另一个线程(主线程)再跑,为什么最后只打印出一个c=0,是因为主线程执行完了,退出了,其他的线程就没有机会执行了。多线程是哪一个线程调度的快,哪一个线程就优先输出,主线程优先输出的话,其他线程就没有机会执行了。
3. channel
a. 管道,类似unix/linux中的pipe(队列)
b. 多个goroute之间通过channel进行通信
c. 支持任何类型
实例9-2
package main import (
"fmt"
) func main() {
p := make(chan int, 3)
p <- 1
p <- 2 var b int
b = <-p
fmt.Printf("b = %d\n", b)
}
输出结果:
解释:
make(chan int,3):chan就是管道类型关键字,int表示管道中放什么类型数据,3表示管道空间,也就是管道的容量
p <- 1:就表示往管道中放数据
b = <- p:表示从管道中把数据取出来给变量b
输出的b的结果为1:,是因为队列先进先出。
注意:
管道容量为3,当放入的数据多于3个时,就会报死锁的错误。
代码如下:
执行结果:
死锁是最近新版本加入,旧的版本会直接卡在哪里等待。
4. 多返回值
a. 一个函数返回多个值
实例9-3
定义多个返回值,就要返回多个,不然会报错,都是一一对应的。
实例9-4
package main import (
"fmt"
) func Calc(a int, b int) (int, int) {
return a + b, a - b
} func main() {
a1, b1 := Calc(2, 5)
fmt.Printf("a1=%d b1=%d\n", a1, b1)
}
执行结果:
Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性的更多相关文章
- [java学习笔记]java语言基础概述之标识符&关键字&注释&常量和变量
一.标识符 在程序中自定义的一些名称 由26个英文字母的大小写,数字,_$组成 定义合法标识符的规则: 不能以数字开头 不能使用关键字 java严格区分大小写 注意:在起名字时,为了提高阅读性,必须得 ...
- Java中关于注释、标识符、变量、常量、数据类型、类型转换、转移字符以及数值型的表现形式的详解
Java文件的注意事项 在同一个Java文件中,可以定义多个类,但是被public修饰的类只能够有一个,并且此类名要与文件名一致. 在同一个类中,可以定义多个方法,但是名字叫做main的方法只能有一个 ...
- Python语言基础-语法特点、保留字与标识符、变量、基本数据类型、运算符、基本输入输出、Python2.X与Python3.X区别
Python语言基础 1.Python语法特点 注释: 单行注释:# #注释单行注释分为两种情况,例:第一种#用于计算bim数值bim=weight/(height*height)第二种:bim=we ...
- 【JAVA零基础入门系列】Day4 变量与常量
这一篇主要讲解Java中的变量,什么是变量,变量的作用以及如何声明,使用变量. 那么什么是变量?对于初学者而言,可以将变量理解为盒子,这些盒子可以用来存放数据,不同类型的数据需要放在对应类型的盒子里. ...
- go标识符、变量、常量
标识符 标识符是用来表示Go中的变量名或者函数名,以字母或_开头.后可跟着字母.数字. _ 关键字 关键字是Go语言预先定义好的,有特殊含义的标识符. 变量 1. 语法:var identifier ...
- python基础(一):变量和常量
变量 什么是变量 变量,用于在内存中存放程序数据的容器.计算机的核心功能就是"计算",CPU是负责计算的,而计算需要数据吧?数据就存放在内存里,例如:将梁同学的姓名,年龄存下来,让 ...
- Java基础系列(11)- 变量、常量、作用域以及变量的命名规范
变量 变量是什么:就是可以变化的量 Java是一种强类型语言,每个变量都必须声明其类型 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=valu ...
- Python语言基础与应用 (P16)上机练习:基本数据类型
本文是笔者在学习MOOC课程<Python语言基础与应用> (北京大学-陈斌)中根据上机课时的要求写下在代码 课程总链接: 中国大学MOOC B站 本节课链接 数值基本运算: 33和7+, ...
- python基础知识(保留字和标识符、变量、常量、基本数据类型)
保留字 保留字是python语言中已经被赋予特定意义的一些单词,开发程序时,不可以作为变量.函数.类.模块和其他对象的名称来使用例如:import 关键字输入后会变色 通过代码进行查看 import ...
- C语言基础知识点整理(函数/变量/常量/指针/数组/结构体)
函数 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...
随机推荐
- MySQL数据库引擎简介
简单说,当你访问数据库时,不管是手工访问,还是程序访问,都不是直接读写数据库文件,而是通过数据库引擎去访问数据库文件.以关系型数据库为例,你发SQL语句给数据库引擎,数据库引擎解释SQL语句,提取出你 ...
- show table detail
create table #t(name varchar(255), rows bigint, reserved varchar(20),data varchar(20), index_size va ...
- 如何选择RDBMS关系型数据库和Nosql非关系型数据库?
RDBMS关系型数据库和Nosql非关系型数据库区别: 一.RDBMS是关系型数据库模式: 1.二维模式,由行列组成. 2.非常强调事务原子性,例如用户提出一个请求,DB完整的去执行,如果报错就全部回 ...
- 关于jdk1.5之后的自定拆装箱
我们都知道jdk在1.5版本之后,增加了一些新特性,我们称之为语法糖,有:1.泛型,2.foreach增强for循环,3.自动拆装箱,4.可变参数,5.枚举,6.静态导入 public class T ...
- HDOJ 1196 Lowest Bit
题目大意是给一个1-100的整数,要求首先转化成2进制,然后从最低位开始数起到不是0的位停止,输出这些位代表队额10进制数 #include <iostream> using namesp ...
- yii2常用excel操作库
yii2使用较多的excel操作库 1."phpoffice/phpexcel" https://github.com/PHPOffice/PHPExcel/archive/1.8 ...
- ubuntu nvidia驱动+cuda9.0
https://blog.csdn.net/fdqw_sph/article/details/78745375
- 监控linux系统的简易脚本
我先把脚本粘贴在这吧,方便大家观看,其中也是借鉴了不少其他大神的东西,这个脚本主要是用来监控服务器.用户.日志,还得创建备份,等等等等.最近学的shell比较多,就用这个来练练手了,比较简单,大家凑合 ...
- 多线程学习-基础(十二)生产者消费者模型:wait(),sleep(),notify()实现
一.多线程模型一:生产者消费者模型 (1)模型图:(从网上找的图,清晰明了) (2)生产者消费者模型原理说明: 这个模型核心是围绕着一个“仓库”的概念,生产者消费者都是围绕着:“仓库”来进行操作, ...
- 使用JMeter的Java Sampler轻松定制自己的benchmark
做性能测试,接口测试,非常好 转自 http://www.iteye.com/topic/1123432 以前碰到更多的是WEB APP的性能测试,也许用得最多的是Loadrunner, Web S ...