一、Go语言的源文件的拓展是.go
开发环境和工具:GOLAND
个人版开发:
企业版开发:
二、Go语言结构
1、package main 定义一个名为main的包名
2、import "fmt" 添加fmt包
3、func main() 是程序开始执行的函数
4、定义变量:var a int = 21 (和C不同,变量名放在了变量类型前面)
5、//单行注释 /*......*/多行注释
在goland编辑器中
单行注释的快捷键是 Ctrl+/
多行注释的快捷键是 Alt+Shift+/
6、fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n
7、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:
Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序
需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小
写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面
向对象语言中 的 protected )
注:
func main()
{ // 错误,{ 不能在单独的行上
fmt.Println("Hello, World!")
}
三、Go语言风格
1.程序一般由关键字、常量、变量、运算符、类型和函数组成
2.Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字:
3.常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
例:显式类型定义: const b string = "abc"
隐式类型定义: const b = "abc"
多重赋值:
const a, b, c = 1, false, "str" //多重赋值
多个相同类型的声明可以简写为:const c_name1, c_name2 = value1, value2
4.常量还可以用作枚举:
const (
Unknown = 0
Female = 1
Male = 2
)
数字 0、1 和 2 分别代表未知性别、女性和男性。
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过
5.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
)
实例
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
6.Go的算数运算符 A=10,B=20
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
-- | 自减 | A-- 输出结果 9 |
7.Go的关系运算符 A=10,B=20
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
8.Go的逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A || B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A & |
9.Go的位运算符
Go 语言支持的位运算符如下表所示。假定 A 为60,B 为13:
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
| | 按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | (A ^ B) 结果为 49, 二进制为 0011 0001 |
<< | 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
10.Go的赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A + B 将 A + B 表达式结果赋值给 C |
+= | 相加后再赋值 | C += A 等于 C = C + A |
-= | 相减后再赋值 | C -= A 等于 C = C - A |
*= | 相乘后再赋值 | C *= A 等于 C = C * A |
/= | 相除后再赋值 | C /= A 等于 C = C / A |
%= | 求余后再赋值 | C %= A 等于 C = C % A |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2 |
11.Go的其它运算符
下表列出了Go语言的其他运算符。
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
12.Go的运算符优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + - | ^ |
3 | == != < <= > >= |
2 | && |
1 | || |
四、Go语言条件语句
1.if语句
(if 语句 由一个布尔表达式后紧跟一个或多个语句组成)
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
例子:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* 使用 if 语句判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" )
}
fmt.Printf("a 的值为 : %d\n", a)
}
以上代码执行结果为:
a 小于 20
a 的值为 : 10
2.if..else语句
(if 语句后可以使用可选的else语句,else语句中的表达式在布尔表达式为 false 时执行)
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
例子:
package main
import "fmt"
func main() {
/* 局部变量定义 */
var a int = 100;
/* 判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" );
} else {
/* 如果条件为 false 则执行以下语句 */
fmt.Printf("a 不小于 20\n" );
}
fmt.Printf("a 的值为 : %d\n", a);
}
以上代码执行结果为:
a 不小于 20
a 的值为 : 100
3.if嵌套语句
(可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句)
if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}
例子:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
/* 判断条件 */
if a == 100 {
/* if 条件语句为 true 执行 */
if b == 200 {
/* if 条件语句为 true 执行 */
fmt.Printf("a 的值为 100 , b 的值为 200\n" );
}
}
fmt.Printf("a 值为 : %d\n", a );
fmt.Printf("b 值为 : %d\n", b );
}
以上代码执行结果为:
a 的值为 100 , b 的值为 200
a 值为 : 100
b 值为 : 200
4.switch语句
( 用于基于不同条件执行不同动作)
switch var1 {
case val1:
...
case val2:
...
default:
...
}
实例:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var grade string = "B"
var marks int = 90
switch marks {
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
fmt.Printf("你的等级是 %s\n", grade );
}
以上代码执行结果为:
优秀!
你的等级是 A
switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。
Type Switch 语法格式如下:
switch x.(type){
case type:
statement(s);
case type:
statement(s);
/* 你可以定义任意个数的case */
default: /* 可选 */
statement(s);
}
实例
package main
import "fmt"
func main() {
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf(" x 的类型 :%T",i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型" )
default:
fmt.Printf("未知型")
}
}
以上代码执行结果为:
x 的类型 :<nil>
使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
实例
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("1、case 条件语句为 false")
fallthrough
case true:
fmt.Println("2、case 条件语句为 true")
fallthrough
case false:
fmt.Println("3、case 条件语句为 false")
fallthrough
case true:
fmt.Println("4、case 条件语句为 true")
case false:
fmt.Println("5、case 条件语句为 false")
fallthrough
default:
fmt.Println("6、默认 case")
}
}
以上代码执行结果为:
2、case 条件语句为 true
3、case 条件语句为 false
4、case 条件语句为 true
总结:从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。
5.select语句
(select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行 )
select {
case <- channel1:
// 执行的代码
case value := <- channel2:
// 执行的代码
case channel3 <- value:
// 执行的代码
// 你可以定义任意数量的 case
default:
// 所有通道都没有准备好,执行的代码
}
实例::::::
package main
import (
"fmt"
"time"
)
func main() {
// 定义两个通道
c1 := make(chan string)
c2 := make(chan string)
// 启动两个 goroutine(协程),分别从两个通道中获取数据
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
// 使用 select 语句非阻塞地从两个通道中获取数据
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
//default:
如果两个通道都没有可用的数据,则执行这里的语句
//fmt.Println("no message received")
}
}
}
以上代码执行结果为:
received one
received two
五、Go语言循环语句
1. for循环语句 (重复执行语句块)
for循环的三种形式:
①.和C一样
for init; condition; post { }
②.和C的while一样
for condition { }
③.和C的for(;;)一样
for { }
- init: 一般为赋值表达式,给控制变量赋初值;
- condition: 关系表达式或逻辑表达式,循环控制条件;
- post: 一般为赋值表达式,给控制变量增量或减量。
六、Go语言函数
go语言的函数格式:
func function_name( [parameter list] ) [return_types] {
函数体
}
/*
函数定义解析:
func:函数由 func 开始声明
function_name:函数名称,参数列表和返回值类型构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。 return_types:返回类型,函数返回一列值。
return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下
return_types 不是必须的。 函数体:函数定义的代码集合。
*/
Go 函数可以返回多个值,例如:
实例:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
以上实例执行结果为:
Runoob Google
七、Go语言数组
1.基础知识:数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1
2.声明数组:
Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
var variable_name [SIZE] variable_type
实例:var balance [10] float32
3.初始化数组:
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
1.如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
2.如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}
注:初始化数组中 {} 中的元素个数不能大于 [] 中的数字/如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小
八、Go语言指针
说明:一个指针变量指向了一个值的内存地址
声明格式如下:
var var_name *var-type
实例:这是一个指向 int 和 float32 的指针
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
九、Go语言切片(简单来说就是动态数组,数组长度可变)
1.定义切片
①声明一个未指定大小的数组(切片不需要说明长度)
var identifier [ ]type
②使用make 函数来创建切片
var slices [ ]type = make([ ] type,len)
简写:slices := make([ ]type,len)
③指容量,其中capacity为可数参数
make([ ]T,length,capacity)
2.切片初始化
①直接初始化切片,[ ]表示切片类型,初始化值依次为1,2,3,其中cap = len = 3
s := [ ]int {1,2,3}
②初始化切片s,是数组arr的引用
s := arr[ : ]
③将数组从下标索引startindex到endindex-1下的元素创建为一个新的切片
s := arr[ startIndex:endIndex ]
④默认endIndex时将表示一直到arr数组最后一个元素表示为一个切片
s := arr[startIndex :]
⑤默认startIndex时将表示从arr的第一个元素开始
s:= arr[ : endIndex]
⑥通过切片s初始化切片s1
s1 = s[startIndex : endIndex]
⑦通过内置函数make()初始化切片s,[]int标识为其元素类型类型为int的切片
s := make([ ]int,len,cap)
十、结构体字段命名及使用范围
package main
import "fmt"
// 定义一个名为 Person 的结构体
type Person struct {
Name string // 可导出的字段
age int // 私有的字段
}
func main() {
// 创建 Person 结构体的实例
p := Person{
Name: "Alice",
age: 25,
}
fmt.Println(p.Name) // 可以访问可导出的字段
// fmt.Println(p.age) // 无法访问私有的字段,会编译错误
}
十一、goland的重构快捷键
十一、函数和接口的区别
- 函数是一段可执行的代码块,用于实现特定的功能,而接口是一种抽象的类型,用于定义一组方法的集合。
- 函数可以独立定义和调用,而接口需要被类型实现才能使用。
- 函数可以接收参数和返回结果,而接口只定义方法的签名,不包含具体的实现。
- 函数通常用于封装可重用的代码逻辑,而接口用于定义多个类型之间的共享行为。
可以使用以下生动的比喻来说明它们之间的区别:
想象一下你是一家快递公司的老板,而函数就像是你的员工,而接口则是你制定的一套操作规范。
-
函数(function)就像是你的员工。每个函数都是一个独立的工作人员,他们各自有自己的任务和职责。你可以将特定的任务分配给不同的函数,并在需要时调用他们。每个函数相当于执行某项具体任务的工人。
-
接口(interface)就像是你制定的操作规范。接口是一套定义了一组方法的规则,描述了工人应该具备的共同行为。你可以制定一份规范,例如所有的工人都必须具备“送货”和“签收”这两种行为。每个工人只要按照规范实现这两个方法,就可以成为符合规范的工人。
使用快递公司的例子,可以更容易理解函数和接口的区别。函数就像是具体的工人,而接口则是定义了工人应该有的共同行为的规范。这样,你可以根据具体的需求,雇佣不同的工人来完成不同的任务。而接口规范则确保了无论是哪位工人,他们都能完成规定的任务,从而保证了快递服务的质量和一致性。