Go语言保证了既能达到静态编译语言的安全和性能,又达到了动态语言开发维护的高效率,使用一个表达式来形容Go语言,Go=C + Python,说明Go语言既有C静态语言程序的运行速度,又能达到Python动态语言的快速开发。
1.从c语言中继承了很多理念,包括表达式语法,控制结构,基础数据类型,调用参数传值,指针等等,也保留了和c语言一样的编译执行方式及弱化的指针。
2.引入包的概念,用于组织程序结构,Go语言的一个文件都要归属于一个包,而不能单独存在。
3.垃圾回收机制,内存自动回收,不需要开发人员管理。
4.天然并发
(1)从语言层面支持并发实现简单
(2)goroutine,轻量级线程,可实现大并发处理,高效利用多核。
(3)基于CSP并发模型(Comminicating Sequential Processes)实现。
5.吸收管道通信机制,形成Go语言特有的管道channel通过管道channel,可以实现不同的goroute之间的相互通信。
6.函数返回多个值。
7.新的创新:比如切片slice、延时执行defer等。
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
go文件的后缀是 .go
package main 表示该 hello.go 文件所在的包是main,在go中,每个文件都必须归属一个包。
import “fmt” 表示引入一个包,包名fmt,引入该包后,就可以使用fmt包的函数,比如:fmt.Println
func main(){} func 是一个关键字,表示一个函数。main是函数名,是一个主函数,即我们程序的入口。
fmt.Println(“hello world”) 表示调用fmt包的函数Println输出"hello world"
生成.exe 可执行文件
直接运行
linux下开发go和windows开发基本一样。只是在运行可以执行的程序时,是以 ./文件名方式
1.如果我们先编译生成了可执行文件,那么我们可以将可执行文件拷贝到没有go开发环境的机器上,任然可以执行。
2.如果我是直接go run go源代码,那么如果要在另一个机器上运行,也想要go开发环境,否则无法执行。
3.在编译时,编译器会将程序运行依赖的库文件包含在可执行文件中,所有可执行文件变大了很多。
自主命名:
go build -o 生成文件名.exe 源文件.go
1.Go源文件以“go”为扩展名
2.Go应用程序的执行入口是main()函数。
3.Go语言是严格区分大小写的。
4.Go方法由一条条语句构成,每个语句后不需要分号(Go语言会在没行后自动加分号),这也体现出了Golang的简洁性。
5.Go编译器是一行行进行编译的,因此我们一行就写一条语句,不能把多条语句写在同一行,否则会报错。
6.Go语言定义的变量或者import包如果没有使用到,代码不能编译通过。
7.大括号都是成对出现的,缺一不可。
和c语言类似
转义字符: |
---|
\n (换行) |
\t (表示一个制表符,通常使用它可以排版) |
\ (转义) |
\r (回车,表示从当前行的最前面开始输出,覆盖掉以前内容) |
行注释: //
块注释: /**/
Go官方推荐使用行注释
1.使用一次tab操作,实现缩进,默认整体向右移动,有时候shift+tab整体向左移动。
2.或使用gofmt来进行格式化
3.运算符两边习惯性各加一个空格。
4.大括号的写法
5.换行用逗号(,)
变量是程序的基本组成单位
变量相当于内存中一个数据存储空间的表示,通过变量名可以访问到变量值。
var 变量名 数据类型
package main
import "fmt"
func main() {
var i int = 10
fmt.Println(i)
}
1.变量表示内存中的一个存储区域
2.该区域有自己的名称(变量名)和类型(数据类型)
3.Golang变量使用的三种方式
(1)指定变量类型,声明后若不赋值,使用默认值
(2)根据值自行判定变量类型(类型推导)
(3)省略var,注意:=左侧的变量不应该事故已声明过的,否则会导致编译错误
4.多变量声明,在编译值,有时候我们需要一次性声明多个变量,Golang也提供这样的语法。
5.该区域的数据值可以在同一类型范围内不断变化
6.变量在同一个作用域内不能重名
7变量=变量名+值+数据类型
8.Golang的变量如果没有赋初值,会赋一个默认值。
package main
import "fmt"
var n7 = 100
var n8 = 200
var name2 = "jt"
//一次声明
var (
n9 = 100
n10 = 200
name3 = "jt"
)
func main() {
//golang的变量使用方式1
//第一种:指定变量类型,声明后若不赋值,使用默认值// int的默认值是e,其它数据类型的默认值后面马上介绍var i int
var i int
fmt.Println("i =", i)
//第二种:根据值自行判定变量类型(类型推导)var num =10.11
var num = 10.11
fmt.Println("num =", num)
//第三种:省略var,注意:=左侧的变量不应该是已经声明过的,香则会导致编译错误1/下面的方式等价var name stringname = "tom"
// :=的:不能省略,否则错误
name := "tom"
fmt.Println("name =", name)
//该案例演示golang如何一次性声明多个变量
var n1, n2, n3 int
fmt.Println(n1, n2, n3)
// 一次性声明多个变量的方式2
var n5, name1, n4 = 108, "tom", 888
fmt.Println(n5, name1, n4)
//一次性声明多个变量的方式3,同样可以使用类型推导
n5, name1, n4 = 108, "tom", 888
fmt.Println(n5, name1, n4)
//输出全局变量
fmt.Println(n7, name2, n8)
fmt.Println(n9, name3, n10)
}
1.当左右两边都是数值型时,则做加法运算
2.当左右两边都是字符串,则做字符串拼接
package main
import "fmt"
//+ 号的使用
func main() {
var i = 1
var j = 2
var r = i + j
fmt.Println(r)
var str1 = "hello"
var str2 = "world"
var str = str1 + str2
fmt.Println(str)
}
类型 | 有无符号 | 占用存储空间 | 数据范围 |
---|---|---|---|
int8 | 有 | 1字节 | -128 ~ 127 |
int16 | 有 | 2字节 | -215 ~ 215-1 |
int32 | 有 | 4字节 | -231 ~ 231-1 |
int64 | 有 | 8字节 | -263 ~ 263-1 |
uint8 | 无 | 1字节 | 0 ~ 255 |
uint16 | 无 | 2字节 | 0 ~ 216-1 |
uint32 | 无 | 4字节 | 0 ~ 232-1 |
uint64 | 无 | 8字节 | 0 ~ 264-1 |
类型 | 有无符号 | 数据范围 | 备注 |
---|---|---|---|
int | 有 | -231 ~ 231-1,-263~263-1 | |
uint | 无 | 0 ~ 232-1,0 ~ 264-1 | |
rune | 有 | -231 ~ 231-1 | 等价int32,表示一个Unicode码 |
byte | 无 | 0 ~ 255 | 当要存储字符是选用byte |
1.Golang各整数类型分:有符号和无符号,int uint的大小和系统有关。
2.Golang的整型默认声明为int型
fmt.Printf("a 的类型 %T", a)//输出数据类型
3.如何在程序查看某个变量的字节大小和数据类型
fmt.Printf("a 的类型 %T a 占用的字节数是 %d", a, unsafe.Sizeof(a))//输出字节大小
4.Golang程序中整型变量在使用时,遵守保小不保大的原则,即:在保证程序正确运行下,尽量使用占用空间小的数据类型。
5.bit:计算机中的最小存储单位。byte:计算机中基本存储单元。1byte = 8 bit
类型 | 占用存储空间 | 表数范围 |
---|---|---|
单精度float32 | 4字节 | -3.403E38 ~ 3.403E38 |
双精度float64 | 8字节 | -1.798E308~ 1.798E308 |
说明一下:
1)关于浮点数在机器中存放形式的简单说明,浮点数=管号拉+指数位+尾数位3.56
11110000111.111111111111111111000
2)尾数部分可能丢失,造成精度损失。-123.0000901
//尾数部分可能丢失,造成精度损失。
var num3 float32 = -123.0000901
var num4 float64 = -123.0000901
fmt.Println("num3=", num3, "num4=", num4)
3)浮点型的存储分为三部分:符号位+指数位+尾数位在存储过程中,精度会有丢失
Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。也就是说对于传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的。
var c1 byte = 'a'
var c2 byte = '0' //字符的0
//当我们直接输出byte值,就是输出了的对应的字符的码值// "a' ==>
fmt.Println("c1=", c1)
fmt.Println("c2=", c2)
//如果我们希望输出对应字符,需要使用格式化输出
fmt.Printf("c1=%c c2=%c\n", c1, c2)
//var c3 byte =‘北’//overflow溢出
var c3 int = '北' //overflow溢出
fmt.Printf("c3=%c c3对应码值=%d", c3, c3)
1.字符常量是用单引号(’’)括起来的单个字符。例如: var c1 byte = ‘a’ , var c2 int=“中” var c3 byte = ‘9’
2.Go中允许使用转义字符尘来将其后的字符转变为特殊字符型常量。例如: var c3 char = ‘\n’ // \n表示换行符
3.Go语言的字符使用UTF-8编码,英文字母是1个字节,汉字是3个字节
4.在Go中,字符的本质是一个整数,直接输出时,是该字符对应的UTF-8编码的码值。
5.可以直接给某个变量赋一个数字,然后按格式化输出时%c,会输出该数字对应的unicode字符
6.字符类型是可以进行运算的,相当于一个整数,因为它都
对应有Unicode码.
1.字符型存储到计算机中,需要将字符对应的码值(整数)找出来
存储:字符->对应码值---->二进制–>存储
读取:二进制---->码值----->字符–>读取
2.字符和码值的对应关系是通过字符编码表决定的(是规定好)
3.Go语言的编码都统一成了utf-8。非常的方便,很统一,再也没有编码乱码的困扰了
bool类型占1个字节。
bool类型适于逻辑运算,一般用于程序流程控制
不可用0或非0的整数代替false和true
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本
Go语言的字符串的字节使用uTF-8编码标识unicode文本,这样Golang统一使用UTF-8编码,中文乱码问题不会再困扰程序员。
字符串一旦赋值了,字符串就不能修改了﹔在Go中字符串是不可变的。
字符串的两种表示形式
1)双引号,会识别转义字符
2)反引号(``),以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果
字符串拼接方式(+)
当一个拼接的操作很长时,怎么办,可以分行写,但是注意,需要将+保留在上一行.
在go中,数据类型都有一个默认值,当程序员没有赋值时,就会保留默认值,在go中,默认值又叫零值。
数据类型 | 默认值 |
---|---|
整数 | 0 |
浮点型 | 0 |
字符串 | “” |
布尔类型 | false |
Golang 和java / c不同,Go在不同类型的变量之间赋值时需要显式转换。也就是说Golang中数据类型不能自动转换。
表达式T(v)将值v转换为类型T
T:就是数据类型,比如int32,int64,float32等等
v:就是需要转换的变量
练习:
var n1 int32 = 12
var n3 int8
var n4 int8
n4 = int8(n1) + 127 //编译通过,会出现溢出
n3 = int8(n1) + 128 //编译不过
fmt.Println(n3)
方式一: fmt.Sprintf("%参数",表达式)
package main
import "fmt"
func main() {
var num1 int = 99
var num2 float32 = 21.11
var b bool = true
var mychar byte = 'h'
var str string //空的str
//使用第一种方式转换 fmt.Sprintf方法
str = fmt.Sprintf("%d", num1)
fmt.Printf("%T,%q\n", str, str)
str = fmt.Sprintf("%f", num2)
fmt.Printf("%T,%q\n", str, str)
str = fmt.Sprintf("%t", b)
fmt.Printf("%T,%q\n", str, str)
str = fmt.Sprintf("%c", mychar)
fmt.Printf("%T,%q", str, str)
}
方式二:使用strconv包的函数
//第二种方式
var num3 int = 99
var num4 float64 = 21.11
var b2 bool = true
str = strconv.FormatInt(int64(num3), 10)
fmt.Printf("%T,%q\n", str, str)
str = strconv.FormatFloat(num4, 'f', 10, 64)
fmt.Printf("%T,%q\n", str, str)
str = strconv.FormatBool(b2)
fmt.Printf("%T,%q\n", str, str)
//strconv包中有一个函数Itoa
var num5 int = 456
str = strconv.Itoa(num5)
fmt.Printf("%T,%q\n", str, str)
1.使用strconvh包的函数
package main
import (
"fmt"
"strconv"
)
func main() {
var str string = "true"
var b bool
b, _ = strconv.ParseBool(str)
fmt.Printf("%T %v", b, b)
var str2 string = "12315"
var n1 int64
n1, _ = strconv.ParseInt(str2, 10, 64)
fmt.Printf("%T %v", n1, n1)
var str3 string = "213.454"
var f1 float64
f1, _ = strconv.ParseFloat(str3, 64)
fmt.Printf("%T %v", f1, f1)
}
在将String类型转成基本数据类型时,要确保String类型能够转成有效的数据,比如我们可以把"123”,转成一个整数,但是不能把"hello”转成一个整数,如果这样做,Golang直接将其转成0
1.基本数据类型,变量存的就是值,也叫值类型
2.获取变量的地址,用&,比如:var num int,获取num的地址:&num
3.指针类型,指针变量存的是一个地址,这个地址指向的空间存的才是值比如: var ptr *int = &num
4.获取指针类型所指向的值,使用:,比如:var ptr * int,使用ptr获取ptr指向的值
1.值类型,都有对应的指针类型,形式为*数据类型,比如int的对应的指针就是 * int, float32对应的指针类型就是 *float32,依次类推。
2.值类型包括:基本数据类型int系列, float系列, bool, string、数组和结构体struct
值类型:基本数据类型 int系列, float系列, bool, string 、数组和结构体struct
引用类型。指针、slice切片、map、管道chan、 interface等都是引用类型
运算符是—种特殊的符号,用以表示数据的运算、赋值和比较等
算术运算符是对数值类型的变量进行运算的,比如:加减乘除。在Go程序中使用的非常多。
i++只能独立使用
Golang 的4+和–只能写在变量的后面,不能写在变量的前面,即,只有 a++ a–没有++a
用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个bool值。
&&也叫短路与:如果第一个条件为false,则第二个条件不会判断,最终结果为false
||也叫短路或。如果第一个条件为true,则第二个条件不会判断,最终结果为true
赋值运算符就是将某个运算后的值,赋给指定的变量。
1)二进制的最高位是符号位:0表示正数,1表示负数
1 ==>[0000 0001]
-1=>[1000 0001]
2)正数的原码,反码,补码都一样
3)负数的反码=它的原码符号位不变,其它位取反(0->1,1->0)
1=>原码[0000 0001]反码[0000 0001]补码[0000 0001]
-1=>原码[1000 0001]反码[11111110]补码[1111 1111]
4)负数的补码=它的反码+1
5)0的反码,补码都是0
6)在计算机运算的时候,都是以补码的方式来运算的.1-1=1+(-1)
步骤:
1)导入fmt包
2)调用fmt包的fmt.Scanln()或者fmt.Scanf()
package main
import "fmt"
func main() {
//方式一:fmt.Scanln
var name string
var age byte
var sal float32
var isPass bool
fmt.Println("请输入姓名")
fmt.Scanln(&name)
fmt.Println("请输入年龄")
fmt.Scanln(&age)
fmt.Println("请输入薪水")
fmt.Scanln(&sal)
fmt.Println("请输入是否通过考试")
fmt.Scanln(&isPass)
fmt.Println(name, age, sal, isPass)
//方式二:fmt.Scanf
fmt.Printf("请输入你的名字,年龄,薪水,是否通过考试,使用空格隔开")
fmt.Scanf("%s %d %f %t", &name, &age, &sal, &isPass)
fmt.Println(name, age, sal, isPass)
}
程序顺序执行
注意格式是固定的与其他语言不同
package main
import "fmt"
func main() {
var i int = 10
if i > 10 {
fmt.Printf("i>10")
} else if i > 20 {
fmt.Printf("i>20")
} else {
fmt.Printf("其他")
}
}
switch语句用于基于不同条件执行不同动作,每一个case分支都是唯一的,从上到下逐一测试,直到匹配为止。
golang的case后的表达式可以有多个,使用逗号间隔
匹配项后面也不需要再加break
golang 中的case 语句块不需要写break,因为默认会有,即在默认情况下,当程序执行完case语句块后,就直接退出该switch控制结构。
package main
import "fmt"
func main() {
var key byte
fmt.Scanf("%c", &key)
switch key {
case 'a':
fmt.Println("你输入了a")
case 'b':
fmt.Println("你输入了b")
default:
fmt.Println("输入错误")
}
}
case后是一个表达式(即:常量值、变量、一个有返回值的函数狰都可以)
case后的各个表达式的值的数据类型,必须和 switch 的表达式数据类型一致
case后面可以带多个表达式,使用逗号间隔。比如case表达式1,表达式2…
case后面的表达式如果是常量值(字面量),则要求不能重复
case后面不需要带break ,程序匹配到一个case后就会执行对应的代码块,然后退出switch,如果一个都匹配不到,则执行default
default语句不是必须的.
switch后也可以不带表达式,类似if --else分支来使用。
switch穿透-fallthrough ,如果在case语句块后增加fallthrough ,则会继续执行下一个case,也叫switch穿透。
Type Switch: switch 语句还可以被用于type-switch来判断某个interface变量中实际指向的变量类型
示例:
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
fmt.Println("hello word!")
}
}
package main
import "fmt"
func main() {
i := 0
for i < 10 {
fmt.Println("hello word!")
i++
}
}
package main
import "fmt"
func main() {
i := 0
for {
fmt.Println("hello word!")
i++
if i >= 10 {
break
}
}
}
Golang 提供for-range的方式,可以方便遍历字符串和数组,案例说明如何遍历字符串。
package main
import "fmt"
func main() {
//方式1:
var str string = "hello world"
for i := 0; i < len(str); i++ {
fmt.Printf("%c\n", str[i])
}
//for-range遍历
str = "asdccc"
for index, val := range str {
fmt.Printf("index=%d,var=%c\n", index, val)
}
}
如果字符串含有中文,传统的对字符串的遍历是按字节遍历的,一个汉字对应三个字节,需要将str 转换为 []rune 切片,对于for-range是按照字符方式编译,有中文不会影响
package main
import "fmt"
func main() {
var str string = "hello 江涛"
str2 := []rune(str)
for i := 0; i < len(str2); i++ {
fmt.Printf("%c\n", str2[i])
}
}
随机数生成:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
//生成1-100的随机数
//设置rand的一个种子
rand.Seed(time.Now().Unix()) //返回一个从1970:01:01的0时0分0秒到现在的秒数
n := rand.Intn(100) + 1
fmt.Println(n)
//随机生成1-100的一个数,直到生成了99这个数,看看你一共用了几次
var count int = 0
for {
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100) + 1
fmt.Println(n)
count++
if n == 99 {
break
}
}
fmt.Println(count)
}
break默认跳出最近的for循环
break配合标签使用
label1:
for {
rand.Seed(time.Now().UnixNano())
n := rand.Intn(1000) + 1
fmt.Println(n)
count++
if n == 999 {
break label1
}
}
package main
import "fmt"
func main() {
//goto的使用
fmt.Println("1")
fmt.Println("2")
goto label1
fmt.Println("3")
fmt.Println("4")
fmt.Println("5")
label1:
fmt.Println("6")
fmt.Println("7")
}
return跳出函数