go基础系列:简介
1.Go简介
Go语言是编译型、静态类型的类C的语言,并带有GC(垃圾收集器,garbage collection)。这意味着什么?
另外,Go是一种非常严格的语言,它几乎总是要求我们"以标准答案去答题",在其它语言可以容忍的不规范编码方式在Go语言中几乎都会抛异常。例如导入了包却没有使用这个包,Go不会去编译它并报错。再例如,定义了一个变量但从来没用过,也会报错。
初学Go的时候,这可能是件无比的苦恼事情,但习惯了之后,编写出来的程序自然是无比规范的。这也正是Go和不少语言的区别:其它语言编码、调试阶段可能很快,但维护和优化阶段可能会非常长;而Go的编码周期可能稍长,但编码完成后几乎都是足够优化的,维护和优化周期足够短。
编译型
编译表示的是将你所写的源代码转换为低层次的语言,例如汇编语言(go采用此底层语言),或者其它中间的语言(如Java、C#编译成字节码)。
编译型语言可能不太友好,因为编译的过程速度很慢。如果一个程序的编译过程就需要花几分钟甚至几小时,那么程序的版本迭代可能会很难进行下去。编译速度是Go语言的一个主要设计目标,值得庆幸的是,Go的编译速度很快,即便对于习惯于使用解释型语言的人来说,它也还是快。
编译型语言虽然编译过程慢,但这类语言在运行阶段可能会更快,而且运行时不再需要加载额外的依赖。
静态类型
静态语言意味着变量必须要指定数据类型(int,string,bool,[]byte等)。虽然必须指定数据类型,但除了在声明变量的时候显式指定数据类型,也可以让Go自己去推断数据类型(稍后有示例)。
对于习惯于使用动态型语言的人来说,可能会感觉静态型语言很笨重,事实确实如此。但静态有静态的好处,特别是配合编译操作的时候。
关于静态和动态数据类型,要说的内容其实很多很多,毕竟对于一门语言来说,数据类型牵一发而动全身,无论是静态、还是动态型语言,都因此而衍生出无数的优、缺点。
类C型的语言
当我们说一门语言是类C型(C-like)的语言时,意味着这门语言里有一些语法和特性和C语言是类似的。例如,&&
表示布尔的AND,==
表示等值比较,数组索引从0开始计算,{...}
表示一段代码块,也表示它属于一个作用域范围,等等。
类C型语言也意味着每行的语句要使用分号";"结束,条件表达式要使用括号包围。但Go语言不采用这两种方式,尽管还是可以使用括号包围条件表达式以改变优先级。例如:
if name == "malongshuai" {
print("name rigth!")
}
一个更复杂一点的条件表达式,使用括号改变优先级:
if (name == "longshuai" && age > 23) || (name == "xiaofang" && age < 22) {
print("yeyeye!!!")
}
GC
每当创建一个变量后,这个变量都会有其生命周期。例如,函数内部的本地变量将在函数退出的时候消逝。对于非函数内部的变量生命周期,无论是对程序员还是对编译器来说,变量的生命周期都没有那么显而易见。
没有garbage collection,意味着要让程序员自己来决定变量所占用内存的释放,这是很艰巨的任务,而且很容易出错导致程序崩溃。
带有GC的语言可以对变量进行跟踪,并且在它们不再被需要的时候自动释放它们。虽然GC带来了一点点的负载,会影响一点点的性能,但对于现在高性能的计算机来说,这点影响相比它带来的优点而言,完全可以将其无视。
尝试写一个简单的Go程序
按照国际管理,每一门语言总是以hello world开篇。这里就算了,因为我有我的惯例。
先安装Go,so easy...
目前还没有必要涉及Go的工作空间,所以随意找个地方创建一个test.go文件,内容如下:
package main
func main() {
println("Let's Go")
}
然后运行:
go run test.go
显然,它将输出Let's Go
。但是Go的编译过程呢?go run
命令同时进行了编译和运行两个过程:它将使用一个临时目录保存构建的程序,然后执行它,最后自动清理构建出来的临时程序。
可以使用go run --work
查看下具体情况:
$ go run --work test.go
WORK=/tmp/go-build267589647
Let's Go
构建的临时目录位于/tmp/go-buildXXXX中(我这是Linux),在此目录下会有一个二进制程序(对于Windows则是.exe文件):
$ tree /tmp/go-build267589647/
/tmp/go-build267589647/
├── command-line-arguments
│ └── _obj
│ └── exe
│ └── test # 这是可执行二进制程序
└── command-line-arguments.a
那个test文件就是编译后得到的二进制程序,可以直接用来执行:
$ /tmp/go-build267589647/command-line-arguments/_obj/exe/test
Let's Go
如果要显式编译,使用go build
命令:
go build test.go
它将在当前目录下生成一个名为test的二进制文件,可以直接拿来运行,就像前面/tmp中的一样。
$ ./tese
Let's Go
在开发阶段,用go build还是用go run,随意即可。但在部署的时候,一般先go build,再go run。
main包和main函数
在上面的代码中,声明了这个包的名称为main,然后创建一个函数,并在此函数中使用println
输出了一个字符串,但是go run
如何知道要去执行什么?在Go中,程序的入口是main包中的main函数,这两名称都是固定的。
对于一个从没编程过的人,可能不理解程序的入口。它表示程序从此处开始执行,函数main中可能会包含很多其它函数的调用,这些函数可能放在其它文件(包)中。通过一次次、一层层的调用,从而将整个程序的所有代码、逻辑都连接在一起并运行。
如果你愿意,可以试着修改一下package后面的main
关键字,然后go run
和go build
都运行一下。再试着修改一下func main
的main
关键字,go run
和go build
再运行一下。
关于包的内容,后面再做介绍。目前来说,需要理解的只是些基础,对于基础阶段来说,我们将总是在main包中写代码。
import
Go有一些内置的函数,例如上面的println
,内置函数无需额外的引用就可直接调用。但内置函数毕竟很少,所以得从已经写好的Go标准库和其它第三方库中找出一些工具来使用。
在Go中,import
关键字用于定义要导入到当前文件的包名,导入某个包后,这个包中的属性就能在当前文件中去访问,例如调用属于这个包的函数。
例如,将前面的代码改改:
package main
import (
"fmt"
"os"
)
func main (){
if len(os.Args) != 2{
os.Exit(1)
}
fmt.Println("Arg0: ",os.Args[0])
fmt.Println("Arg1: ",os.Args[1])
}
执行一下:
$ go run test.go
exit status 1
$ go run test.go a b
exit status 1
$ go run test.go a
Arg0: /tmp/go-build730099388/command-line-arguments/_obj/exe/test
Arg1: a
上面的import导入了两个标准包:fmt
和os
,还使用了另一个内置函数len()
。
len()
函数返回字符串的长度、字典的元素个数以及数组的元素个数。上面使用len()判断了该Go程序的参数个数必须为2,否则就以状态码1退出该程序。看上面的运行结果,好像只有给一个参数的时候才是正确的,这是因为第一个参数(Args[0]
)代表的总是当前正在运行的程序名称,正如上面结果所显示的那样。
你可能还注意到了fmt.Println
,前缀fmt
正好是导入的一个包名,这表示使用fmt包中的Println函数。
本文的开头就说过了,Go是一门非常严格的语言,如果这里导入了fmt包,但却没有使用它,它将报错。
# command-line-arguments
./test.go:4:5: imported and not used: "fmt"
关于Go文档
关于fmt的Println函数详细用法,可去参考Go的官方文档:https://golang.org/pkg/fmt/#Println。当然,现阶段去看官方手册,那是在找死。
还可以使用go doc
命令去查找各帮助文档。
例如,查看fmt包的帮助文档:
go doc fmt
查看fmt.Println
函数的用法:
go doc fmt.Println
完整用法:
go doc
go doc <pkg>
go doc <sym>[.<method>]
go doc [<pkg>].<sym>[.<method>]
go doc <pkg> <sym>[.<method>]
此外,还可以构建本地的网页版官方手册,在断网的时候可以访问:
godoc -http=:6060
然后就可以在浏览器中通过http://localhost:6060/
访问官方手册。
变量和变量声明
很多语言中,要为变量赋值只需一个语句:
x=10
这个语句中实际上包含了两个过程:变量的声明和变量的赋值。声明一般也被称为"定义"。
在Go中,必须先声明变量,再赋值或使用变量。最复杂的声明+赋值操作为:
package main
import ( "fmt" )
func main(){
var x int
x=10
fmt.Println("x =",x)
}
此处声明了一个变量x,其数据类型为int
。默认情况下,Go在变量的声明期间会为其做初始化赋值:int类型初始化赋值为0,booleans初始化赋值为false,strings初始化赋值为"",等等。
可以将声明和赋值操作合并:
var x int = 10
还有一种更方便的声明+赋值方式:
x := 10
通过这种变量的定义方式,还可以将函数执行结果(返回值)赋值给变量。例如:
func main() {
x := getAdd(10)
}
func getAdd(x int) int {
return x+1
}
:=
在Go中属于类型推断操作,它包含了变量声明和变量赋值两个过程。
需要注意的是,变量声明之后不能再次声明(除非在不同的作用域),之后只能使用=
进行赋值。例如,执行下面的代码将报错:
package main
import ("fmt")
func main(){
x:=10
fmt.Println("x =",x)
x:=11
fmt.Println("x =",x)
}
错误如下:
# command-line-arguments
.\test.go:8:3: no new variables on left side of :=
报错信息很明显,:=
左边没有新变量。
如果仔细看上面的报错信息,会发现no new variables
是一个复数。实际上,Go允许我们使用:=
一次性声明、赋值多个变量,而且只要左边有任何一个新变量,语法就是正确的。
func main(){
name,age := "longshuai",23
fmt.Println("name:",name,"age:",age)
// name重新赋值,因为有一个新变量weight
weight,name := 90,"malongshuai"
fmt.Println("name:",name,"weight:",weight)
}
需要注意,name第二次被:=
赋值,Go第一次推断出该变量的数据类型之后,就不允许:=
再改变它的数据类型,因为只有第一次:=
对name进行声明,之后所有的:=
对name都只是简单的赋值操作。
例如,下面将报错:
weight,name := 90,80
错误信息:
.\test.go:11:14: cannot use 80 (type int) as type string in assignment
另外,变量声明之后必须使用,否则会报错,因为Go对规范的要求非常严格。例如,下面定义了weight
但却没使用:
weight,name := 90,"malongshuai"
fmt.Println("name:",name)
错误信息:
.\test.go:11:2: weight declared and not used
可以一次性声明、声明并赋值多个变量:
var x, y, z int
x, y, z := 10, 20, 30
var (
x = 10
y = 20
z = 30
)
函数定义
Go的函数允许有多个返回值。例如:
// 该函数有一个参数,没有返回值
func log(message string){
...CODE...
}
// 该函数有两个参数,一个返回值,返回值的类型为int
func add(a int,b int) int {
...CODE...
}
// 该函数一个参数,两个返回值,分别是int和bool
func power(name string) (int,bool) {
...CODE...
}
既然函数可以有返回值,就可以将其返回值赋值给变量:
value, exists := power("malongshuai")
if exists == false {
...CODE...
}
有些时候,我们可能并不需要所有的返回值。例如,我们只想要取得power()的第二个返回值。这时可以将不想要的返回值丢给特殊符号下划线_
,它表示丢弃这部分结果。
_,exists := power("longshuai")
if exists == false {
...CODE...
}
如果函数的参数类型相同,则不同的参数可以共享数据类型。
func (a,b int) int {
...CODE...
}
go基础系列:简介的更多相关文章
- 2.JSR简介 - JavaEE基础系列
JSR, Java Specification Request, Java规范请求; 也有的地方翻译为Java规范提案. 在前面的文章 1. Java EE简介 - JavaEE基础系列中, 简要介绍 ...
- 夯实Java基础系列15:Java注解简介和最佳实践
Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...
- 【Machine Learning】机器学习及其基础概念简介
机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
- 大数据入门基础系列之Hadoop1.X、Hadoop2.X和Hadoop3.X的多维度区别详解(博主推荐)
不多说,直接上干货! 在前面的博文里,我已经介绍了 大数据入门基础系列之Linux操作系统简介与选择 大数据入门基础系列之虚拟机的下载.安装详解 大数据入门基础系列之Linux的安装详解 大数据入门基 ...
- mybatis基础系列(一)——mybatis入门
好久不发博客了,写博文的一个好处是能让心静下来,整理下之前学习过的一些知识一起分享,大神路过~ mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射. ...
- 4. 什么是应用服务器? - JavaEE基础系列
本文是JavaEE基础系列的第四节. Java EE简介 - JavaEE基础系列 JSR简介 - JavaEE基础系列 什么是JSR参考实现? - JavaEE基础系列 上一节介绍了什么是JSR参考 ...
- 3. 什么是JSR参考实现? - JavaEE基础系列
本文是JavaEE基础系列的第三节. Java EE简介 - JavaEE基础系列 JSR简介 - JavaEE基础系列 上一节中, 我们介绍了什么是JSR.JSR就是一个提交到JCP的抽象请求,包含 ...
- 夯实Java基础系列1:Java面向对象三大特性(基础篇)
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...
- 夯实Java基础系列5:Java文件和Java包结构
目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...
- 夯实Java基础系列7:一文读懂Java 代码块和执行顺序
目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...
随机推荐
- [swarthmore cs75] Compiler 6 – Fer-de-lance
课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第8次大作业. First-class function: It treats function ...
- Core Expression
https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm A Cron Expressions Cro ...
- lucene之Field属性的解释
Field类 数据类型 Tokenized是否分词 Indexed 是否索引 Stored 是否存储 说明 StringField(FieldName, FieldValue,Store.YES)) ...
- hdu 1052 Tian Ji -- The Horse Racing【田忌赛马】
题目 这道题主要是需要考虑到各种情况:先对马的速度进行排序,然后分情况考虑: 1.当田忌最慢的马比国王最慢的马快则赢一局 2.当田忌最快的马比国王最快的马快则赢一局 3.当田忌最快的马比国王最快的马慢 ...
- jdango
1.jdango的下载 命令行: pip install django ==1.11.18 pip install django ==1.11.18 -i https://pypi.douban.co ...
- 26.HashCode
在前面三篇博文中讲解了(HashMap.HashSet.HashTable),在其中不断地讲解他们的put和get方法,在这两个方法中计算key的hashCode应该是最重要也是最精华的部分,所以 ...
- select count(*) 底层究竟做了什么?
阅读本文大概需要 6.6 分钟. SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表 ...
- 吴恩达机器学习笔记8-多变量线性回归(Linear Regression with Multiple Variables)--多维特征
我们探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(
- Im4java 操作 ImageMagick 处理图片
背景 之前用的是JMagick,各种限制各种坑,直到使用了Im4java,真是相当的好用啊. 项目描述 ImageMagic的安装可参考:图片处理软件 ImageMagick 的安装和使用 Im4ja ...
- CSS3实现背景透明文字不透明
最近遇到一个需求,如下图,input框要有透明效果 首先想到的方法是CSS3的 opacity属性,但事实证明我想的太简单了 这个属性虽然让input框有透明效果,同时文字和字体图标也会有透明效果,导 ...