前言
任何新技术的出现:无非是出于2种原因,相对之前无非是提升了效率 或者 使用这种技术更加便捷。
go语言是一种新型的开源计算机编程语言,天然利用了 多核优势 性能优越支持大并发,go开发的代码编译后 可以在Windows和Linux环境到处运行 不用额外装什么Java、Python环境、配置环境变量....
轻松地支持大并发
代码部署简单
这2点深深吸引了我。
/* 在写go代码的开始一定要声明,当前的文件属于什么类型的包, 定义了1个main包 也就是可独立执行的程序 每1个go程序都应该包含1个main包 */ package main /* 导入1个包 */ import "fmt" /* 定义程序启动后 执行的第1个main函数*/ func main() { fmt.Println("Hello Martin") } /* go文件是以.go结尾的文件 必须包含在1个目录下 */
一、什么是go语言
Google开源
2007年在Google公司内部萌芽的语言,2009年Google讲go正式开源
编译性语言
Python、php代码都是由解释器 把代码翻译成字节码 一边解释一边执行,而go、c、c++是编译工具编译成二进制文件 直接交给操作系统执行。
所有编译性语言和解释型语言对比 少了1个中间翻译的环节,执行起来就会更快,在部署这些程序的时 也比较简便 因为不需要下载解释器,只需要把二进制可执行文件copy到服务器 交给操作系统执行二进制文件即可。

21世纪的C语言

C、C++、Python、Ruby、JavaScript都诞生于 多核出现之前(2005年),而go语言出现在多核时代之后,所以 go在设计支持就考虑到了适配多核CPU,天生支持了并发,不需要像Python借助 借助第三方的库、复杂的语法糖 支持并发。
go语言设计的宗旨就是 简化了c的语法兼顾了c的性能 所以go=c+python

执行go代码
1.go run
解释执行 go文件
D:\goproject\src\hello>go run hello.go
Hello Martin
2. go build
把go文件编译成二进制文件
2.1在代码所在目录下编译
D:\goproject\src\hello>go build hello.go
2.2 在其他目录下编译go代码
需要指定 go文件的路径但是 也就是 go path\src\目录后面的路径,这样做的结果是你什么路径下执行的go build 那个编译好的 二进制文件就在什么路径下
C:\Users\Administrator.PC-20170811HMNW> go build code.zhanggen.com\studygo\day01\hello
2.3 go build -o 指定二进制文件名
D:\goproject\src\hello>go build -o 爱叫啥叫啥
3.go install
编译二进制文件 + 把编译好的二进制文件自动放在 gopath/bin目录下
D:\goproject\src\hello>go install hello
4.交叉编译(跨平台编译)
我们一般在Windows/Mac开发 去Linux部署,那么如何在Windows、Mac平台编译出Linux可以执行二进制文件呢?
Windows ----Linux
D:\goproject\src\hello>SET CGO=ENABLED=0 //禁用CGO D:\goproject\src\hello>SET GOOS=linux D:\goproject\src\hello>SET GORACH=adm64 D:\goproject\src\hello>go build hello.go
Mac ---Linux
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Linux ------- Mac
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
Linux-----Windows
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Windows ---Mac
SET CGO_ENABLED=0 SET GOOS=darwin SET GOARCH=amd64 go build
Go程序的目录结构
在go path下的
bin:go install 编译源码 之后 可执行二进制文件存储目录
pkg:go install 编译源码 之后 包文件存储目录
src:存放所有程序员开发的go源码
注意:在go 11.1之前,每1个.go文件都要存放到gopath/src

变量
变量是编程语言中一种管理数据的机制,当数据赋值给变量之后,该数据就可以在程序中反复使用,避免被GC回收掉;
Go是一门静态语言 不同于Python、JavaScript 等动态语言 变量声明时就要指定数据类型、声明之后如果是局部变量 就必须要使用否则会编译不通过。
还有1个很大不同Go的执行语句都必须写在函数里面,函数外面只能声明变量 、声明函数。
注意事项:
a.函数外的每个语句必须以关键字开始(var、const、func)
b. :=只能使用于函数内,不能使用在函数外
c._多用于占位,表示忽略
d.同一个作用域中 不能同时声明2个相同的变量
package main
import "fmt"
//Go语言推荐使用驼峰式命名
//变量既可以声明在函数体内也可以声明在函数体外
var name string
var age int
var isOk bool //Go语言推荐使用驼峰式命名
//批量声明 不用每次都写个 var
var (
name1 string //没有赋值前默认为空字符 ""
age1 int //没有赋值前默认为0
isOk1 bool //没有赋值前默认为false
)
//变量初始化(对声明的变量进行赋值)
func main() {
name = "Martin"
age = 18
isOk = true
//Print 在终端打印不会加换行
fmt.Print(name1)
//Println 打印内容后面自动加上换行
fmt.Println(age1)
//Printf支持内容格式化输出
fmt.Printf("name:%s age:%d isOk: %t", name, age, isOk)
var name2 string
name2 = "Martin2" //name2 declared and not used
fmt.Println() //打印1换行
fmt.Print(name2) //变量只要在函数内 声明之后 就必须要使用 否则会编译不通过
}
声明变量+赋值
package main
import "fmt"
func main() {
//声明变量的同时赋值
var name3 string = "Martin3"
//数据类型自动推到
var age3 = 20
//简短变量声明(只能用于函数)
isOk3 := false
fmt.Println(name3, age3, isOk3)
}
变量的作用域
在go语言中 1个大括号{},就会开辟1个新的作用域。
package main
import "fmt"
//const plan string = "earch"
//
//var hunman bool = true
//func main() {
//name:="martin"
//nation:="chinese"
//if name=="martin"{
// //在go语言中 1个大括号{},就会开辟1个作用域。
// age:=88
// name:="xxx"
// fmt.Println(name)
// fmt.Println(age)
// fmt.Println(nation)
//}
//fmt.Println(name)
//fmt.Println(nation)
////fmt.Println(age) //pinic.\main.go:11:14: undefined: age
//fmt.Println(plan, hunman)
//}
//赋值变量和内存
//func fun1(name,nickName string) {
// //0xc000027f58 0xc000027f38
// println(&name,&nickName)
//}
//值类型的变量:数字、字符串、布尔这3种数据类型是,如果遇到变量赋值,则会重新拷贝一份。
//func main() {
// name:="武沛齐"
// nickName:=name
// println(&nickName,&name)
// //0xc000027f48 0xc000027f68
// fun1(name,nickName)
// name="alex"
// println(name,nickName)
// println(&nickName,&name)
//
//}
var number int = 666
func main() {
println(&number)//0x563230
if true{
number=888 //修改变量的值666---》8888,但是不会重新开辟内存。
fmt.Println(&number)//0x563230
}
fmt.Println(number)
}
不同的变量声明
不同的变量声明方式,在golang的编译器编译时,在内层上所做的操作不同。
1.声明变量
var v1 int //开辟1块个内存+内存初始化值位0,v1指向该内存地址,打印显示0 fmt.Println(v1) v2:=999 //开辟1块个内存+内存初始化值设置为999,v2指向该内存地址,打印显示0 fmt.Println(v2)

2.声明指针类型的变量
在Go语言中指针是1种可以把内存地址存储起来的数据类型。
我们使用指针数据类型的变量,可以记录下另1个变量的内存地址,方便我们快速查询到这个变量并对该变量的值进行修改。
所以别人一提到指针,我们脑海中一定要出现 2块内存而不是1块。
其中内存1存着 内存2的地址, 内存2存储着1个我们想要的value。它们又都有自己的内存地址。
我们通过内存1这个跳板跳到内存2上获取值。
var v3 *int fmt.Printf("编译器开辟1块名为:%p的内存 存储了1个%p的空指针,空指针指向了nil(并没有初始化)\n",&v3,v3) v4:=new(int) fmt.Printf("编译器开辟1块名为:%p的内存 存储了1个指针%p,指针指向%p内存这块内存上存了值(new进行了初始化)%d\n",&v4,v4,&*v4,*v4)
new 和 make 的区别
- new 和 make 是 Go 语言中用于创建对象的两个关键字,它们的主要区别如下:
- new 用于创建值类型的对象,而 make 用于创建引用类型的对象。
- new 返回对象的指针,而 make 返回对象本身。
- new 创建的对象的字段会被初始化为零值,而 make 创建的对象会被正确地初始化
为什么需要new和make两个不同的关键字呢?
这是因为值类型和引用类型在内存中的存储方式和初始化方式有所不同。值类型的对象通常直接存储在栈上,而引用类型的对象则存储在堆上,并通过指针来访问。
因此,用 new 关键字创建值类型对象时,返回的是对象的指针,而使用 make 关键字创建引用类型对象时,返回的是对象本身。
此外,值类型的对象在创建时会被初始化为零值,而引用类型的对象需要经过初始化过程,以确保其内部结构和字段的正确性。
const 常量
程序目录结构、变量声明 +赋值 、 开始感受到Go的严谨了,常量就是一经声明和赋值之后在程序运行期间不会动态修改更改的变量。
package main
import "fmt"
//声明1个常量
const pi = 3.14
//批量声明常量
const (
StatusOk = 200
PathNotFind = 404
)
//批量声明常量时 如果常量没有指定类型并赋值的情况下,变量值和上一行一致。
const (
n1 = 100
n2 //没有赋值默认值为该变量上面的值 也就是100
n3
)
func main() {
fmt.Printf("n1:%d n2:%d n3:%d", n1, n2, n3)
}
常量+变量总结
package main
import "fmt"
//先申明变量再赋值
var name0 string
//全局变量因式分解
var (
name1 = "Martin1"
name2 = "Martin2"
)
//全局常量因式分解
const (
age0= 0
age1=1
)
func main() {
//1.定义变量的6种方式
name0 = "Martin0"
var name3 string = "Martin3"
var name4 = "Martin4"
name5 := "Martin5"
fmt.Println(name0, name1, name2, name3,name4,name5)
//2.定义常量的2种方式
const age2 int8 =2
const age3 = 3
fmt.Println(age0,age1,age2,age3)
}
iota常量计数器
iota 是go语言中的常量计数器,只能在常量的表达式中使用。Iota常量计数器的作用是可以方便我们生产一堆值为连续的数字的变量。
在这堆变量中任意1个变量被注释,都不用重新组织数字的连续,他会自动连续排列起来。
const( x6 =iota+6 x7 //x8 当x8变量不使用时, x9 //x9=8. )
以上我们提到我们批量声明常量时,如果常量没有指定类型并赋值的情况下,变量值和上一行一致。
而在const中声明了iota常量,每新增1行常量声明将使 iota 计数 +1,在const 中遇到 _跳过1个数字。
iota常量计数器只能在const中使用,而且不同的const中声明的iota常量,相互不干扰。 (所以 iota在 遇到下1个const关键字时,会被打回0。)
package main
import "fmt"
const (
a=iota //0
b=10 //10
c //10
d,e=iota,iota //3,3
f=iota /4
)
func main() {
fmt.Println(a,b,c,d,e,f)
}
package main
import "fmt"
//示例1
const (
v1 =1
v2 =2
v3 =3
v4 =4
v5 =5
)
//示例2
const (
v6=iota+6
v7
v8
v9
_ //中间间隔1个值
v11
v12
)
const (
v13=iota //iota在遇到const关键字时,会被打回0。
v14=iota
v15=iota
)
//iota是声明常量时的1个计数器
func main() {
fmt.Println(v1,v2,v3,v4,v5) //1 2 3 4 5
fmt.Println(v6,v7,v8,v9,v11,v12) //6 7 8 9 11 12
fmt.Println(v13,v14,v15) //0 1 2
}
package main
import "fmt"
//声明1个常量
const pi = 3.14
//批量声明常量
const (
StatusOk = 200
PathNotFind = 404
)
//批量声明常量时 没有赋值的情况下默认和上一行一致
const (
n1 = 100
n2 //没有赋值默认值为该变量上面的值 也就是100
n3
)
//iota
const (
a0 = iota //0
a1 = iota //1
a2 = iota //2
)
const (
b0 = iota
b1 //b1=iota
_
b2
)
//iota 插队
const (
c1 = iota
c2 = 100
c3
c4 = iota //3每新增1行 iota +1 由于新增的2行 iota=3
c5
)
//多个常量声明在1行
const (
d1, d2 = iota + 1, iota + 2 //d1=0+1,d2=0+2 注意:因为常量声明在了同行所有 不会加1
d3, d4 = iota + 1, iota + 2 // d3=1+1,d4=1+2
)
//定义数量级
const (
_ = iota
KB = 1 << (10 * iota) //1左移 10位
MB = 1 << (10 * iota) //1左移 20位
GB = 1 << (10 * iota) //1左移 30位
TB = 1 << (10 * iota) //1左移 40位
PB = 1 << (10 * iota) //1左移 50位
)
func main() {
// fmt.Printf("a0:%d a1:%d a2:%d", a0, a1, a2)
// fmt.Printf("b0:%d b1:%d b2:%d", b0, b1, b2)//0 1 3
//fmt.Printf("c1:%d c2:%d c3:%d c4:%d c5:%d", c1, c2, c3, c4, c5) //0 100 100 100
// fmt.Print(d1, d2, d3, d4)
fmt.Print(KB, MB, TB, PB)
}
Go文件基础语法总结
编程语言就是人类和计算机交流的工具,就像人类和人类之间交流使用的汉语、英语、日语、汉语一样,由于发明和使用它们的人们地域、文化、思想、追求、价值不同,所以它们的语法和风格有不同之处,但除了地域不同之外 我们也有很多相同之处。
I like sunny girl who has long brown hair.
我喜欢一个开朗、有着棕色的长头发的女孩。
咬文嚼字地分析一下汉字和英文
英语:先说我喜欢阳光的姑娘,然后再丰富具体的细节。(先说重点.....再慢慢补充)
中文:把所有形容词都形容出来了再说表语 (先慢慢铺垫....最后出现重点)
虽然中文和英文的有些语法不同, 但2句话最终要做的事情是一样的 约会。
学会采用 2者对比的方式 来记忆、学习、理解不同的东西。
-------------------------------------------------------------------------------------------------------------
1.存放Go源代码的文件后缀名以.go结尾不是.py了
2.文件第一行 使用 package main声明文件作用类型(声明这是 1个可执行文件?还是写得1个供别人调用使用的模板)
3.如果是1个可执行的文件,必须要有main包和main函数,这个mian函数也是程序执行的入口
4.Go语言函数体外的语句必须以关键字(var、func、const)开头(不像Python那样在py文件里任意位置 写什么代码都行)
5.函数内部的变量必须使用(所以Go中有哑元变量 _ ,它的作用就是仅接收变量 但不使用)
fmt.scan()输出
fmt.scan可以帮助我们向用户提供1个输入接口,完成程序和用户输入的交互。
1.fmt.Scan()
fmt.Scan会一直等待用户输入指定个数的值,输入完成回车结束。
package main
import "fmt"
func main() {
//示例1
//var name string
//fmt.Print("请输入用户名: ")
//fmt.Scan(&name)
//fmt.Println(name)
//示例2:输入2个值
var (
name string
age int8
)
fmt.Print("请输入姓名和年龄以空格隔开: ")
//当用户完成输入之后
//Scan会得到2个返回值:counter用户输入了几个值, err输入错误信息
counter, err := fmt.Scan(&name, &age)
if counter == 2 && err == nil {
fmt.Println(name, age)
} else {
fmt.Println("输入错误")
}
}
2.fmt.Scanln()
fmt.Scanln()不会一直等待用户输入指定个数的值,只要用户按了回车键,输入就完成。
counter, err := fmt.Scanln(&name, &age)
if counter == 2 && err == nil {
fmt.Println(name, age)
} else {
fmt.Println("输入错误")
}
3.fmt.Scanf()
一定要按照固定的模板输入:name 和age才能被匹配到!变量后要加空格!
//示例4 Scanf
counter, err := fmt.Scanf("天王盖%s %d 层宝塔镇河妖!", &name, &age)
if counter == 2 && err == nil {
//一定要按照固定的模板输入:name 和age才能被匹配到!
fmt.Println(name, age)
//请输入姓名和年龄以空格隔开: 天王盖地虎 18 层宝塔镇河妖
//地虎 18
} else {
fmt.Println("输入错误",err)
}
print和fmt输出
和Python类似,Go语言中也内置函数print()。帮助我们输出。但是官网说不能保证以后是否存在。推荐使用fmt包进行输出。
Go里面使用fmt这个包实现打印输出的功能,但是这个包里面的方法有很多,不像Python里面就1个print()全部搞定。
目前printf支持以下格式的输出,例如:
printf("%c",a);输出单个字符。
printf("%d",a);输出十进制整数。
printf("%f",a);输出十进制浮点数.
printf("%o",a);输出八进制数。
printf("%s",a);输出字符串。
printf("%u",a);输出无符号十进制数。
printf("%x",a);输出十六进制数。
package main
import (
"fmt"
)
func main() {
//fmt
var n1 = 100
FirstName='张'
name := "张根"
fmt.Printf("%T\n", n1) //查看变量的数据类型
fmt.Printf("%b\n", n1) //查看2进制
fmt.Printf("%o\n", n1) //查看8进制
fmt.Printf("%d\n", n1) //查看10进制
fmt.Printf("%x\n", n1) //查看16进制
fmt.Printf("%s\n", name) //查看字符串
fmt.Printf("%v\n", name) //查看变量值
fmt.Printf("%#v\n", name) //打印带双引号的"变量值"
fmt.Printf("%c",FirstName) //打印字符
}
浙公网安备 33010602011771号