Go入门语法 | 青训营
HelloWorld
package main
import "fmt"
func main() {
fmt.Print("hello,world")
}
第一行 package main 代表这个文件属于 main 包的一部分,main 包也就是程序的入口包。
第三行导入了标准库里面的 FMT 包。这个包主要是用来往屏幕输入输出字符串、格式化字符串。
import 下面是 main 函数,main 函数的话里面调用了 fmt.Println 输出 helloword,fmt包是标准格式化输入输出包。
变量
package main
import (
"fmt"
"math"
)
func main() {
var a = "str"
ab := "str2"
var b, c int = 1, 2
var d = true
var e float64
f := float64(e)
g := a "test"
fmt.Println(a, b, c, d, e, f, g, ab)
fmt.Print(a, " ", b, c)
const s = "constant"
const h = 5000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}
- 完整的变量声明。 var name type
- 声明并初始值 var name type = value
- 自动类型推断 var name = value
- 声明多变量 var name1,name2 = 'liwentong1','liwentong2'
- 简短声明: name2 := 'string'
自动类型推断
如果变量有初始值,那么 Go 能够自动推断具有初始值的变量的类型,声明时可以省略type
变量重声明
对已声明过的变量再次声明
- 重声明的类型与原有类型是一致的。
- 重声明只能使用短声明的方式,进行重声明。
- 重声明发生在当前代码快。而除此本代码块的重声明,就需考虑作用于范围。
package main
import "fmt"
func addNum(a,b int) int {
return a b
}
func main(){
var a int
a,b := 1,2
var c = addNum(a,b)
if b != 0 {
a := 32 //在此代码块中重声明,那表示在此代码块中,对a重新进行了声明。此会覆盖此代码块外的a=2的声明。并且此时a的作用域,也仅在此代码块中。
fmt.Println(a)
}
fmt.Println(a) //此处的a,是外层的变量a。 a=1。
fmt.Println(c)
}
go语言是一门强类型语言,每一个变量都有它自己的变量类型。
常见的变量类型包括 字符串 整数 浮点型、布尔型等。
go 语言的字符串是内置类型,可以直接通过加号拼接,也能够直接用等于号去比较两个字符串。
在go语言里面,大部分运算符的使用和优先级都和 C 或者 C 类似
常量就是把 var 改成const,值在一提的是go语言里面的常量,它没有确定的类型,会根据使用的上下文来自动确定类型。
空值
go中的空值为nil
选择语句
package main
import "fmt"
func main() {
//无字符类型,直接打印成ascll码
fmt.Println('a')
if 7%2 == 0 {
fmt.Println("even")
}
if num := 9; num < 0 {
fmt.Println('1')
}
}
if条件不加括号,后面的代码块必须包大括号。可以在条件语句中声明并初始化一个变量,并在同一行中对该变量进行条件判断。
循环语句
没有while,只有for循环
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println("ok")
break
}
for j := 7; j < 9; j {
fmt.Println(j)
}
for n := 0; n < 5; n {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i 1
}
}
三段for可任意省略。在 for 后面什么都不写,代表一个死循环。
分支语句
package main
import (
"fmt"
"time"
)
func main() {
i := 4
switch i {
case 1:
fmt.Println("1")
case 2, 3:
fmt.Println("2,3")
fmt.Println("2,3")
default:
fmt.Println("other")
}
now := time.Now()
switch {
case now.Hour() < 12:
fmt.Println("bf")
default:
fmt.Println("af")
}
}
在c 里面, switch case 如果不加 break 的话会然后会继续往下跑完所有的 case, 在go语言里不需要加 break 。
可以使用任意的变量类型,甚至可以取代任意的 if else 语句。你可以在 switch 后面不加任何的变量,然后在 case 里面写条件分支。这样代码相比你用多个 if else 代码逻辑会更为清晰。
数组
package main
import "fmt"
func main() {
//声明数组方式
var a [5]int
ints := [5]int{1, 2, 3, 4, 5}
//可以索引访问,也可以调用函数或直接打印全部
ints[2] = 1
fmt.Println(ints[1], a[1])
fmt.Println(len(a), ints)
//多维数组及用法
var two [2][4]int
twoD := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
for i := 0; i < 2; i {
for j := 0; j < 4; j {
two[i][j] = i j
}
}
fmt.Println(two, twoD)
}
切片
切片不同于数组可以任意更改长度,然后也有更多丰富的操作
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2])
fmt.Println("len:", len(s)) //3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) //[a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) //[a b c d e f]
fmt.Println(s[2:5]) //[c d e]
fmt.Println(s[:5]) //[a b c d e]
fmt.Println(s[2:]) //[c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) //[g o o d]
}
用 make 来创建一个切片,可以像数组一样去取值,使用 append 来追加元素。注意 append 的用法的话,你必须把 append 的结果赋值为原数组。
slice 的原理实际上是它存储了长度和容量,加指向数组的指针,在你执行 append 操作的时候,如果容量不够的话,会扩容并且返回新的 slice。
slice 此初始化的时候也可以指定长度。
slice 拥有像 python 一样的切片操作,比如这个代表取出第二个到第五个位置的元素,不包括第五个元素。不过不同于python,这里不支持负数索引
map
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(m["one"])
fmt.Println(m["null"])
//结果和是否存在
result, ok := m["null"]
fmt.Println(result, ok)
//删除元素
delete(m, "one")
//其他声明方式
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
完全无序,遍历时按随机顺序
range
可以对slice或map进行快速遍历
遍历slice时会返回两个值:index,value;遍历map时返回:key,value。可以用下划线来忽略
package main
import "fmt"
func main() {
a := []int{11, 22, 33, 44}
for _, v := range a {//打印index value
fmt.Println(v)
}
m := map[string]string{"a": "A"}
for s, s2 := range m {//打印key value
fmt.Println(s, " ", s2)
}
for s := range m {//打印key
fmt.Println(s)
}
}
函数
go中变量类型是后置的
Golang 里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二个值是一个错误信息。
package main
import "fmt"
//后置变量类型
func add(a int, b int) int {
return a b
}
//可以统一声明类型
func add2(a, b int) int {
return add(a, b)
}
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
i := add2(1, 2)
fmt.Println(i)
fmt.Println(exists(map[string]string{"a": "A"}, "a"))
}
命名返回值:Go语言支持命名返回值。命名返回值就像在函数顶部声明的变量,函数结束时会自动返回它们的当前值。
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
函数作为参数或返回值
package main
import (
"fmt"
"strings"
)
// 定义一个函数类型
type StringFunc func(string) string
// 将函数作为参数传入
func ApplyStrFunc(s string, f StringFunc) string {
return f(s)
}
// 返回一个函数
func MakeAppendFunc(suffix string) StringFunc {
return func(s string) string {
return s suffix
}
}
func main() {
// 将函数作为参数传入
fmt.Println(ApplyStrFunc("hello", strings.ToUpper)) // 输出 "HELLO"
// 返回一个函数并使用它
appendWorld := MakeAppendFunc(" world")
fmt.Println(appendWorld("hello")) // 输出 "hello world"
}
首先定义了一个StringFunc
类型,它是一个接收一个字符串并返回一个字符串的函数类型。然后定义了一个ApplyStrFunc
函数,它接收一个字符串和一个StringFunc
类型的函数,然后将字符串传给StringFunc
并返回结果。
在MakeAppendFunc
函数中,我们返回了一个StringFunc
类型的函数,这个返回的函数会将一个后缀添加到传入的字符串上。
在main
函数中,先使用ApplyStrFunc
函数将字符串"hello"
转换为大写,然后创建了一个appendWorld
函数,这个函数会在传入的字符串后添加" world"
,然后我们使用这个函数将"hello"
转换为"hello world"
。
指针
go中指针的操作有限,主要用途就是对于传入参数进行修改
package main
import "fmt"
func add2np(n int) {
n = 2
}
func add2ptr(i *int) {
*i = 2
}
func main() {
i := 5
add2np(i)
fmt.Println(i)//5
add2ptr(&i)
fmt.Println(i)//7
}
结构体
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{"name", "password"}
b := user{name: "name", password: "password"}
c := user{name: "name"}
c.password = "123"
var d user
d.name = "zfb"
d.password = "password"
fmt.Println(a, b, c, d)
fmt.Println(checkPassword(a, "password"))
fmt.Println(checkPassword2(&a, "password"))
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
构造时可以直接传所有字段值,也可以用键值对制定初始值。
结构体方法
package main
import "fmt"
type user2 struct {
name string
password string
}
func main() {
a := user2{"name", "password"}
b := user2{name: "name", password: "password"}
c := user2{name: "name"}
c.password = "123"
var d user2
d.name = "zfb"
d.password = "password"
fmt.Println(a, b, c, d)
fmt.Println(c.checkPassword("123"))
c.setPassword("321")
fmt.Println(c.password)
}
func (u user2) checkPassword(password string) bool {
return u.password == password
}
func (u *user2) setPassword(password string) {
u.password = password
}
在Go中,可以为任何类型定义方法,包括结构体。结构体的方法定义在结构体之外,但需要在函数名前加上一个参数,这个参数代表调用该方法的结构体实例。在实现结构体方法时也有两种写法,一种是带指针,一种是不带指针。如果带指针的话,就可以对这个结构体去做修改。不带指针的话,实际上操作的是一个拷贝,就无法对结构体进行修改。
错误处理
package main
import (
"errors"
"fmt"
)
type user3 struct {
name string
password string
}
func finduser3(user3s []user3, name string) (v *user3, err error) {
for _, u := range user3s {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := finduser3([]user3{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) //wang
if u, err := finduser3([]user3{{"wang", "1024"}}, "q"); err != nil {
fmt.Println(err) //not found
return
} else {
fmt.Println(u.name)
}
}
错误处理通常通过函数的多返回值来实现。函数可以返回一个错误值,如果这个值不是nil,那么就表示有错误发生。
字符串操作
package main
import (
"fmt"
"strings"
)
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "llo"))
fmt.Println(strings.Count(a, "l"))
fmt.Println(strings.HasSuffix(a, "llo"))
fmt.Println(strings.Index(a, "ll"))
fmt.Println(strings.Join([]string{"he", "llo"}, " "))
//返回将a中前n个不重叠e子串都替换为E的新字符串,如果n<0会替换所有e子串。
fmt.Println(strings.Replace(a, "e", "E", -1))
fmt.Println(strings.Split("1[2[3", "["))
fmt.Println(len(a))
fmt.Println(len("中")) //中文占3字符长
}
- 判断子串:
strings.Contains(a, "llo")
函数检查字符串a
("hello")是否包含子串"llo"。返回一个布尔值,如果a
包含"llo",则返回true
。 - 计数子串:
strings.Count(a, "l")
函数计算字符串a
中字符"l"的数量。返回一个整数,表示字符"l"在a
中的出现次数。 - 判断后缀:
strings.HasSuffix(a, "llo")
函数检查字符串a
是否以子串"llo"结束。返回一个布尔值,如果a
以"llo"结尾,则返回true
。 - 查找子串:
strings.Index(a, "ll")
函数查找子串"ll"在字符串a
中首次出现的索引位置。返回一个整数,表示子串在a
中的起始位置。如果a
中不包含"ll",则返回-1。 - 连接字符串:
strings.Join([]string{"he", "llo"}, " ")
函数使用空格" "将字符串切片中的所有元素连接起来,形成一个新的字符串。 - 替换子串:
strings.Replace(a, "e", "E", -1)
函数将字符串a
中所有的"e"替换为"E"。最后一个参数-1表示替换所有的匹配项。 - 分割字符串:
strings.Split("1[2[3", "[")
函数根据"["符号将字符串"1[2[3"分割为多个子串,返回一个包含所有子串的切片。 - 获取字符串长度:
len(a)
函数返回字符串a
的长度,即字符数。Go中的len()
函数计算的是字符串中的字节数,而非Unicode字符数。对于ASCII字符,字节数和字符数是相同的。但对于非ASCII字符,如中文字符,一个字符由三个字节组成。
字符串格式化
package main
import "fmt"
type point struct {
x, y int
}
func main() {
p := point{1, 2}
fmt.Printf("p=%v\n", p)
fmt.Printf("p=% v\n", p)
fmt.Printf("p=%#v\n", p)
f := 3.14159
fmt.Printf("f=%.2f\n", f)
}
fmt.Printf("p=%v\n", p)
:这里的%v
是一个通用的值表示,对于结构体,它会输出结构体的字段值,但不会输出字段名。所以这行代码会输出:p={1 2}
。fmt.Printf("p=% v\n", p)
:% v
也是一个通用的值表示,不过对于结构体,它会同时输出字段名和字段值。所以这行代码会输出:p={x:1 y:2}
。fmt.Printf("p=%#v\n", p)
:%#v
是一个更详细的值表示,它会输出Go语法格式的值。对于结构体,它会输出结构体的类型名、字段名和字段值。所以这行代码会输出:p=main.point{x:1, y:2}
。fmt.Printf("f=%.2f\n", f)
:这里的%.2f
表示以浮点数形式输出,且小数部分保留两位。所以这行代码会输出:f=3.14
。
可以使用%v打印任意类型变量,使用% v,%#v打印更详细的结果
JSON处理
package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{"wang", 18, []string{"Golang", "Java"}}
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(string(buf))
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b)
}
- 定义数据结构:
userInfo
结构体被定义,包含三个字段:Name、Age和Hobby。Age字段有一个结构体标签,它会影响JSON序列化和反序列化时该字段的名称。 - 初始化数据:创建了一个
userInfo
类型的变量a
,并初始化为一个具有特定名字、年龄和爱好的用户。 - 序列化数据:使用
json.Marshal()
函数将a
实例序列化为JSON格式的字节流。如果序列化过程中出现错误,程序会panic
并终止运行。之后,使用json.MarshalIndent()
函数将a
实例序列化为带有缩进的JSON格式的字节流,使其更易读。 - 反序列化数据:使用
json.Unmarshal()
函数将序列化的JSON数据反序列化为userInfo
类型的实例。如果反序列化过程中出现错误,程序会panic
并终止运行。
使用json.Marshal(),json.MarshalIndent()序列化实例,后者可以对其进行格式化。使用json.Unmarshal()进行反序列化。
在结构体字段后面添加标签设置该字段序列化和反序列化时使用的key
`json:"age"`
运行结果:
{"Name":"wang","age":18,"Hobby":["Golang","Java"]} { "Name": "wang", "age": 18, "Hobby": [ "Golang", "Java" ] } main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "Java"}}
时间处理
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now)
date := time.Date(2023, 5, 14, 12, 2, 0, 0, time.UTC)
date2 := time.Date(2023, 5, 15, 12, 1, 0, 0, time.UTC)
fmt.Println(date.Format("2006-01-02 15:04:05"))
sub := date2.Sub(date)
fmt.Println(sub)
fmt.Println(sub.Hours(), sub.Seconds())
parse, err := time.Parse("2006-01-02 15:04:05", "2023-02-03 11:23:33")
if err != nil {
panic(err)
}
fmt.Println(parse == date2)
//时间戳
fmt.Println(now.Unix())
}
- 获取当前时间:使用
time.Now()
函数获取当前时间,并将其存储在变量now
中,然后打印出来。 - 创建特定时间:使用
time.Date()
函数创建了两个特定的时间点date
和date2
。这两个函数的参数分别是年份、月份、日期、小时、分钟、秒钟、纳秒以及时区。在这个例子中,时区被设置为UTC。 - 格式化时间:使用
date.Format()
函数将date
变量的时间格式化为"2006-01-02 15:04:05"的形式。这种时间格式化的模板在Go中是固定的。 - 计算时间差:使用
date2.Sub(date)
计算date2
和date
之间的时间差,返回的是一个time.Duration
类型的值,并打印出来。然后通过sub.Hours()
和sub.Seconds()
将时间差转换为小时和秒的形式。 - 解析时间字符串:使用
time.Parse()
函数将字符串"2023-02-03 11:23:33"解析为时间。解析的格式与之前的格式化相同,也是"2006-01-02 15:04:05"。然后将解析得到的时间与date2
比较,检查两者是否相等。 - 获取时间戳:使用
now.Unix()
函数将now
变量的时间转换为Unix时间戳,即从1970年1月1日开始计算的秒数,并打印出来。
数字解析
package main
import (
"fmt"
"strconv"
)
func main() {
float, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(float)
//设置进制
i, _ := strconv.ParseInt("1321", 10, 64)
fmt.Println(i)
//0代表自动推断进制
i2, _ := strconv.ParseInt("0x99A1", 0, 64)
fmt.Println(i2)
atoi, _ := strconv.Atoi("13121342")
fmt.Println(atoi)
}
- 解析浮点数:
strconv.ParseFloat("1.234", 64)
函数尝试将字符串"1.234"解析为浮点数。第二个参数64表示解析的浮点数为64位(float64)。解析成功后,该函数返回解析得到的浮点数和一个nil
错误。 - 解析十进制整数:
strconv.ParseInt("1321", 10, 64)
函数尝试将字符串"1321"解析为整数。这里的第二个参数10表示解析的是十进制的数。第三个参数64表示解析的整数为64位(也就是int64
)。 - 自动推断进制解析整数:
strconv.ParseInt("0x99A1", 0, 64)
函数尝试将字符串"0x99A1"解析为整数。这里的第二个参数0表示函数会根据字符串的前缀("0x"或"0")自动推断要解析的进制:如果是"0x"或"0X"开头,则解析为十六进制;如果是"0"开头,则解析为八进制;否则解析为十进制。 - 解析整数:
strconv.Atoi("13121342")
函数尝试将字符串"13121342"解析为整数。这是strconv.ParseInt(s, 10, 0)
的简写,直接解析为int
类型。这个函数通常在你不关心具体的int
位数(32位还是64位)时使用。
进程信息
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Args) // 打印命令行参数
fmt.Println(os.Getenv("PATH")) // 打印PATH环境变量
fmt.Println(os.Getppid()) // 打印父进程ID
fmt.Println(os.Getpid()) // 打印当前进程ID
}
os.Args
:打印出程序启动时的所有命令行参数。os.Getenv("PATH")
:打印出PATH环境变量的值,它是由冒号分隔的目录列表,用于搜索可执行文件。os.Getppid()
:打印出父进程的ID。对于由shell直接启动的程序,其父进程通常是shell。os.Getpid()
:打印出当前进程的ID。每个运行的程序都有一个唯一的进程ID。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhbjeb
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01