Go语言基础
Go语言官网:https://golang.org/
go中文社区:https://studygolang.com
go中文在线文档:https://studygolang.com/pkgdoc
第一个程序
注释:
- 单行注释 //
-
多行注释 /* */
// 第一个程序 project main.go
// 导入主函数的包
package main
// 系统会导入所需的包 format 标准输入输出包
import (
"fmt"
)
func main() {
//在屏幕打印helloworld
fmt.Println("helloworld")
}
变量
变量:在程序运行过程中其值能够改变的量 成为变量 变量存在内存中
内存:一个连续的数据集合,每一个内存存储区域都有唯一的地址标识,称为内存地址
计算机能够识别的数据形式 :二进制(0 1 10 11 100)
八进制(0 1 2 3 4 5 6 7)
十进制(0 1 2 3 4 5 6 7 8 9 10)
十六进制(0 1 2 3 4 5 6 7 8 9 A(10)B(11)C(12) D(13) E(14)F(15)10)
#定义和声明的区别是是否赋值
var 变量名 数据类型 //变量声明
var a int
var 变量名 数据类型 = 值 //变量定义
var a int=10
变量名:=值 //自动推导类型
a:=10
多重赋值格式
变量1,变量2:=值1,值2
a,b:=10,20
交换a,b的值
# 第一种方法:
temp = a
a = b
b = temp
# 第二种方法:
a = a + b
b = a - b
a = a - b
# 第三种方法:
a, b = b, a
fmt.Println(a, b)
匿名变量
接收这个数据,但是不做存储
_,b,c:=10,20,30
fmt.Println(b,c)
输出格式
# Println 打印数据时自动换行
# Println 打印数据不换行
# %d 占位符 表示输出一个整形数据
# %f 占位符 表示输出一个浮点型数据
# \n 表示转义字符 相当于换行符
# %f 占位符 默认保留6位小数
# %3f 表示小数点后面保留三位 会对第四位进行四舍五入
# bool布尔 string字符串 byte字符
# 声明bool类型变量 默认值为 false true
# %t 占位符 表示输出一个布尔类型数据
# %s 占位符 表示输出一个字符串类型数据
# %c 占位符 表示输出一个字符类型数据
格式化输入输出
&:取地址运算符
fmt.Println() //输出数据 自带换行
fmt.Print() //输出数据 不带换行
fmt.Printf() //格式化输出数据 %d 整型 %f 浮点型 %t 布尔类型 %s 字符串类型 %c 字符类型 %p 内存地址
var name string
var passwd string
fmt.Println("请输入用户名")
fmt.Scanf("%s",&name)
fmt.Println("请输入密码")
fmt.Scanf("%s",&passwd)
fmt.Println(name,passwd)
数据类型
布尔型
var a bool
浮点型
var a float64
字符串类型
var a string
字符和字符串的区别
在go语言中汉字是3个字符,为了和linux同一处理
func main() {
//计算字符串的个数
var b string = "传智播客"
num := len(b)
fmt.Println(num)
}
12
常量
常量:在程序运行过程中 其值不能发生改变的量称之为常量
常量的存储位置在数据区,不能通过& 取地址来访问,变量的存储位置在栈区 系统会为没一个应用程序分配1M空间用来存储变量,在程序运行结束后会自动释放
const B int = 30 //常量一般用大写字母表示
iota枚举
func main() {
const (
a = iota //0
b = iota //1
c = iota //2
d = iota //3
)
fmt.Println(a, b, c, d)
0 1 2 3
func main() {
const (
a = iota
b, c = iota, iota
d, e
)
fmt.Println(a, b, c, d, e)
}
0 1 1 2 2
算术运算符,赋值运算符,逻辑运算符,关系运算符
流程控制
if
func main() {
var a, b, c int
fmt.Println("请输入三只小猪的体重")
fmt.Scan(&a, &b, &c)
if a > b {
if a > c {
fmt.Println("a重")
} else {
fmt.Println("c重")
}
} else {
if a < b {
if b > c {
fmt.Println("b重")
} else {
fmt.Println("c重")
}
}
}
}
switch
//if 可以嵌套 可以判断区间 执行效率比较低
//switch 执行效率高 整洁 不能嵌套和区间判断
func main() {
var w int
fmt.Scan(&w)
//switch中的值不能是浮点型数据 浮点型数据是一个约等于数据
switch w {
case 1:
fmt.Println("今天是星期一")
case 2:
fmt.Println("今天是星期二")
case 3:
fmt.Println("今天是星期三")
//如果输入的值没有找到 默认进入default
default:
fmt.Println("输入错误")
}
}
fallthrough //让switch执行下一个分支的代码 如果不写 执行到下一个分支就会自动停止
1 3 5 7 8 10 12 月份都是31天,我们可以这样写
func main() {
var w int
fmt.Scan(&w)
switch w {
case 1:
fallthrough
case 3:
fallthrough
case 5:
fallthrough
case 12:
fmt.Println("31天")
default:
fmt.Println("输入错误")
}
}
for
基本语法结构如下:
for 表达式1;表达式2;表达式3{
循环体
}
表达式1:定义一个循环的变量,记录循环的次数
表达式2:一般为循环条件,循环多少次
表达式3:一般为改变循环条件的代码,使循环条件终有一天不再成立
循环体:重复要做的事情。
表达式2为假的时候,for循环停止
//打印1-10
func main01() {
//for函数格式 i是在函数内部定义的 不能在外部进行使用
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
}
//计算1-100的总和
func main() {
sum := 0
for i := 1; i <= 100; i++ {
sum = sum + i
}
fmt.Println(sum)
}
循环嵌套
嵌套循环中 执行次数为外层*内层
func main() {
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
fmt.Println(i, j)
}
}
}
跳出循环
break //在循环中 跳出循环
continue//结束本次循环 继续下次循环
func main05() {
//break 在循环中跳出循环
//在嵌套循环中 跳出本层循环
for i:=0;i<=100;i++ {
//奇数
if i%2==1{
//结束本次循环继续下次循环
continue
}
fmt.Println(i)
}
}
//
导出所有偶数
练习
水仙花:一个三位数,100-999 各个位数的立方和如果等于这个数本身,这个数就是一个水仙花数
func main() {
for i := 100; i < 1000; i++ {
a := i / 100
b := i % 100 / 10
c := i % 10
if a*a*a+b*b*b+c*c*c == i {
fmt.Println(i)
}
}
}
函数
定义
func 函数名(函数参数列表){
代码体/函数体
}
在函数定义过程中 函数的参数称为形参 形式参数
形参和实参是不同的存储单元 在函数调用过程中 不会相互影响
在函数调用中使用的是实参 在函数定义中使用的形参
func add(a int, b int) {
var sum int
sum = a + b
fmt.Println(sum)
}
func main() {
var a, b int
fmt.Scanf("%d", &a) // 取地址运算符
fmt.Scanf("%d", &b)
add(a, b)
}
不定参函数调用
不定参函数 : 函数参数类型为 ...数据类型
func add(arr ...int) {
sum := 0
for i := 0; i < len(arr); i++ {
sum = sum + arr[i]
}
fmt.Println(sum)
}
func main() {
add(1, 2, 3, 455)
add(1, 2, 1, 32, 656)
}
//
461
692
用range遍历元素信息 有两个返回值 必须接受 第一个值是下标 第二个值是数据值
func add(arr ...int) { //前面的名字自定义
sum := 0
for i := 0; i < len(arr); i++ { len()计算不定参数的长度
sum = sum + arr[i]
}
fmt.Println(sum)
}
func plus(are ...int) {
sum := 0
//用range遍历元素信息 有两个返回值 必须接受 第一个值是下标 第二个值是数据值
for _, data := range are { //_,匿名变量 丢弃数据不进行处理 在这里我们用不到下标所以丢弃
//date 也可以自定义
sum = sum + data
}
fmt.Println(sum)
}
func main() {
plus(1, 2, 3, 455)
add(1, 2, 1, 32, 656)
}
函数嵌套调用
函数的作用域是全局的 可在项目的任意文件使用 不需要在意先后顺序想
func test1(a int, b int) {
sum := a + b
fmt.Println(sum)
}
func test2(a1 int, b1 int) {
test1(a1, b1)
}
func main() {
test2(1, 2)
}
3
func test1(arr ...int) {
for i := 0; i < len(arr); i++ {
fmt.Println(i, arr[i])
}
}
func test2(b ...int) {
//如果函数参数为不定参 传递方式为b[0:]...
test1(b[0:]...)
//从下标为2开始传
test1(b[2:]...)
}
func main() {
test2(1, 1, 1, 1, 1)
}
函数返回值
格式:func 函数名(形参列表)返回值类型列表{代码体}
return可以写一个表达式 将表达式的结果作为返回值
return表示函数的结束return后面的代码不会执行 同时return会把函数的返回值 传递给主调函数
func sub(a int, b int) int {
sum := a - b
fmt.Println(sum)
return sum
fmt.Println("ssss")
fmt.Println("ssdd")
return 0
}
func main() {
sub(10, 30)
}
以上代码也可改成
func sub(a int, b int) (value int) {
sum := a - b
fmt.Println(sum)
return value
fmt.Println("ssss")
fmt.Println("ssdd")
return 0
}
func main() {
sub(10, 30)
}
函数多个返回值
func test() (a, b, c int) {
a, b, c = 1, 5, 6
return
}
func main() {
//函数的返回值可以为主调函数赋值 可以通过返回值改变实参数据
//如果函数有多个返回值 但是不使用返回值 可以用匿名变量接收数据
a, _, c := test()
fmt.Println(a, c)
}
函数类型
type可以定义函数类型
type可以为已存在的类型起别名
我们可以看到下面test1的函数类型被定义为TYPE1 test2 和test3同理被定义为TYPE2和TYPE3
func test1() {
fmt.Println("askdkasj")
}
func test2(a int, b int) {
fmt.Println(a + b)
}
func test3(a int, b int) int {
return a * b
}
//type可以定义函数类型
//type可以为已存在的类型起别名
type TYPE1 func()
type TYPE2 func(int, int)
type TYPE3 func(int, int) int
func main() {
//定义函数类型变量
var f TYPE1
f = test1
//通过函数变量调用函数
f()
//函数类型 其实就是一个指针
var f1 TYPE2
var f2 TYPE3
f2 = test3
v := f2(3, 5)
fmt.Println(v)
f1 = test2
f1(10, 30)
}
函数数据作用域
1.局部变量:在函数内部定义的变量 作用域限定于本函数的内部 从变量定义到本函数结束有效
2.在同一作用域范围内 变量名是唯一的
3.程序中 如果出现了相同的变量名 如果本函数有自己的变量 就使用自己的 如果没有上外层寻找变量
4.如果名字相同会采用就近原则 使用自己的变量
func main() {
a := 10
{
a := 355
fmt.Println(a)
}
fmt.Println(a)
}
355
10
5.全局变量:在函数外部定义的变量称为全局变量
6.全局变量作用域是项目中的所有文件
7.全局变量在内存中数据区存储 和const定义的常量存储位置都是数据区
var a int = 10 //如果全局变量没有初始值为0
//全局常量
const b int = 66
func demo() {
fmt.Println(b)
fmt.Println(a)
}
func main() {
demo()
//采用就近原则使用局部变量
//在局部变量作用域范围内 全局变量不起作用
a := 35
fmt.Println(a)
}
66
10
35
匿名函数
前面我们定义函数的时候,发现是不能在一个函数中,再次定义一个函数。如果我们想在一个函数中再定义一个函数,那么可以使用匿名函数,所谓匿名函数就是没有名字的函数。
func main() {
a := 10
b := 20
//匿名内部函数
func(a int, b int) {
fmt.Println(a + b)
}(a, b)
}
func main() {
a := 10
b := 20
//f是函数类型对应的变量
f := func(a int, b int) {
fmt.Println(a + b)
}
f(a, b)
f(20, 30)
}
func main() {
a := 10
b := 20
//匿名函数 带返回值的匿名函数
f := func(a int, b int) int {
return a + b
}
//函数调用 f 函数类型 v 接受返回值 类型为int
v := f(a, b)
fmt.Println(v)
}
闭包
//可以通过匿名函数和闭包实现函数在栈区的本地化操作
func test2() func() int {
var a int
return func() int {
a++
return a
}
}
func main() {
//将test2函数类型赋值给f
//f := test2 返回值类型是func func ()int
//函数调用将test2的返回值给f
f := test2() //返回值类型是func()int
for i := 0; i < 10; i++ {
fmt.Println(f())
}
fmt.Printf("%T", f)
}
递归函数
如果一个函数在内部不调用其他的函数,而是自己本身的话,这个函数就是递归函数。递归很消耗资源,消耗内存。能不使用尽量不会使用。
//计算阶乘
// 根据递归计算阶乘
package main
import (
"fmt"
)
var sum int = 1
func test(n int) {
if n == 1 {
return
}
test(n - 1)
sum *= n
}
func main() {
test(5)
fmt.Println(sum)
}
120