不到1000行,Go语言就算入门了吧
Posted 境悟初
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不到1000行,Go语言就算入门了吧相关的知识,希望对你有一定的参考价值。
作为已经掌握了 C、Java、Python、javascript
等多种语言的我们,再学习个新语言,自然不需要重头开始。
建立在已有基础上学习一般都会更快,张三丰那种无招胜有招?抱歉,我目前还达不到。
不过即便如此,断断续续花个几小时把Go语言学会了,也是有诸多好处。毕竟作为一名资深Java开发者,有预感,Go语言会超越Java。
语言罢了,还都是GC语言,不过如此,确实简单。
下面是不到1000行的学习笔记,包含了Go的关键特点,入个门足矣。
基本规则
- go是静态类型语言
- 短变量声明:
var a int = 1
等价于a := 1
- 公开访问的名称规则:大写开头就是公开访问的
- 常用 go命令:
got build xxx.go, go run xxx.go
if true{}
或者for i:=1;i<10;i++{}
后面的括号()是多余的- 导包有多层时用斜杠:
import "math/rand"
读取输入与类型转换
package main
import (
"bufio"
"log"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
s, err := reader.ReadString('\\n')
if err != nil {
log.Fatal(err)
}
age, err := strconv.ParseInt(strings.TrimSpace(s), 10, 32)
age2, err := strconv.Atoi(strings.TrimSpace(s))
println("age=", age, ",age2=", age2)
}
读取文本文件
package main
import (
"bufio"
"log"
"os"
)
func main() {
file, err := os.Open("go.mod")
if err != nil {
log.Fatal(err)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
println(scanner.Text())
}
err = file.Close()
if err != nil {
log.Fatal(err)
}
}
随机数包
package main
import (
"math/rand"
"time"
)
func main() {
fixed := rand.Intn(100) + 1
milli := time.Now().UnixMilli()
rand.Seed(milli)
randInt := rand.Intn(100) + 1
println(fixed, randInt)
}
循环:for也能当while用
package main
func main() {
for i := 0; i < 10; i++ {
print(i, ",")
}
// while
j := 1
for j < 10 {
print(j, ",")
j++
}
for i := 0; i < 10; i++ {
if i < 4 {
break
}
if i > 3 {
continue
}
}
}
函数与返回错误
多个返回值
package main
import "fmt"
func main() {
a, err := area(3, 5)
println("3*5=", a, err)
}
func area(len int, width int) (int, error) {
if len < 0 || width < 0 {
return 0, fmt.Errorf("错误参数:%d,%d", len, width)
}
return len * width, nil
}
指针
package main
import "fmt"
func main() {
a := 2
p := myPointer(&a)
fmt.Println(a, p, *p) // 4 0xc0000200e0 10
}
func myPointer(number *int) *int {
*number *= 2
a := 10
return &a
}
多模块
通过 go init mod 01
初始化,然后实现以下结构。
├── go.mod
├── hello
│ ├── chinese
│ │ ├── chinese.go
│ │ ├── dialect
│ │ │ ├── dialect.go
│ │ │ └── lang.go
│ │ └── putonghua
│ │ └── putonghua.go
│ └── english
│ └── english.go
├── main.go
└── README.md
go.mod
module 01
go 1.17
chinese.go
package chinese
func Hello() {
println("你好")
}
dialect.go
package dialect
func Hello() {
siChuanHua()
dongBeiHua()
}
lang.go
package dialect
func siChuanHua() {
println("瓜娃子")
}
func dongBeiHua() {
println("你瞅啥")
}
putonghua.go
package putonghua
func Hello() {
println("您好呀")
}
english.go
package english
import "fmt"
func Hello() {
fmt.Println("Hello")
}
main.go
开始引用这些包, 从mod名开始。
package main
import (
"01/hello/chinese"
"01/hello/chinese/dialect"
"01/hello/chinese/putonghua"
"01/hello/english"
)
func main() {
english.Hello()
chinese.Hello()
putonghua.Hello()
dialect.Hello()
}
下载三方包
设置代理
go env -w GOPROXY=https://goproxy.cn,direct
go get github.com/xxx/xxx
自己发布包
建一个新仓库,我的示例:https://gitee.com/halfgold/go-test-mod
版本号通过打 git tag来定。
然后在项目里引用:
go.mod
module 03
go 1.17
require (
gitee.com/halfgold/go-mod-test/sing v0.0.1
)
main.go
package main
import "gitee.com/halfgold/go-mod-test/sing"
func main() {
sing.Song()
}
不过很不幸,gitee测试会弹出输入密码的报错:
$ go get gitee.com/halfgold/go-mod-test/sing@v0.0.1
go: gitee.com/halfgold/go-mod-test/sing@v0.0.1: reading gitee.com/halfgold/go-mod-test/sing/sing/go.mod at revision sing/v0.0.1: git ls-remote -q origin in /home/jack/go/pkg/mod/cache/vcs/522776bd8367d68a9aaaca87075c70c40767d41e0e33cc6e07bd270c38fbf6ff: exit status 128:
fatal: could not read Username for 'https://gitee.com': terminal prompts disabled
Confirm the import path was entered correctly.
If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.
既然这样,我就输以下嘛:
$ export GIT_TERMINAL_PROMPT=1
jack@jack-f1:~/workspace/git/go-in/03-go-get$ go get gitee.com/halfgold/go-mod-test/sing@v0.0.1
Username for 'https://gitee.com': halfgold
Password for 'https://halfgold@gitee.com':
go: gitee.com/halfgold/go-mod-test/sing@v0.0.1: reading gitee.com/halfgold/go-mod-test/sing/sing/go.mod at revision sing/v0.0.1: git ls-remote -q origin in /home/jack/go/pkg/mod/cache/vcs/522776bd8367d68a9aaaca87075c70c40767d41e0e33cc6e07bd270c38fbf6ff: exit status 128:
remote: 404 not found!
fatal: 仓库 'https://gitee.com/halfgold/go-mod-test/' 未找到
结果他居然说找不到。
这就伤心了,先存个档。
文档
使用 go doc xxx
查看文档,比如 go doc fmt
.
更详细的:
$ go doc fmt Println
package fmt // import "fmt"
func Println(a ...interface{}) (n int, err error)
Println formats using the default formats for its operands and writes to
standard output. Spaces are always added between operands and a newline is
appended. It returns the number of bytes written and any write error
encountered.
我们也要写文档
我们初始化的04项目写上:包注释和方法注释:
想必看出来规则了:
- 包注释:Package 包名 注释内容
- 方法注释:方法名 注释内容
// Package hello 这个包很牛逼
package hello
// Hello 说你好的方法
func Hello() {
println("你好")
}
展示文档:
04-go-doc$ go doc
package hello // import "04"
Package hello 这个包很牛逼
func Hello()
04-go-doc$ go doc hello
package hello // import "04"
func Hello()
Hello 说你好的方法
安装go的工具集后,可以在网页上展示文档:
sudo apt install golang-golang-x-tools
# 然后起服务
$ godoc -http=:8080
在页面上访问: localhost:8080/pkg
,还能看到自己的包
数组与切片
先看数组的声明和遍历
package main
func main() {
var arr = [3]string{"a", "b", "c"}
arr[0] = "a1"
for i, s := range arr {
println(i, s)
}
var colors [3]int
colors[0] = 1
println("长度:", len(colors))
}
再看切片,可以利用 append
方法延长数组切片
package main
import "fmt"
func main() {
// 数组
var arr [3]int
// 切片
var slice = make([]int, 3)
// 预填充
slice1 := []int{1, 2, 3}
slice2 := slice1[0:2]
slice3 := slice1[1:]
// 修改依赖的底层元素,切片也跟着改变
slice1[1] = 22
fmt.Println(slice3)
// 追加新元素,不会影响原有切片
slice31 := append(slice3, 4, 5)
fmt.Println(slice31, slice1)
slice4 := slice1[:3]
fmt.Println(arr, slice, slice1, slice2, slice3, slice4)
}
可变参数
注意切片传输的写法
package main
func main() {
println(sum(1, 2, 3))
intSlice := []int{1, 2, 3}
println(sum(intSlice...))
}
func sum(nums ...int) int {
sum := 0
for _, n := range nums {
sum += n
}
return sum
}
map
package main
import "fmt"
func main() {
// 初始化
var m map[string]int
m = make(map[string]int)
m["jimo"] = 18
fmt.Println(m)
// map字面量
m = map[string]int{"hehe": 20, "lily": 19}
fmt.Println(m)
// 区分是否设了值
age, hasSet := m["hehe"]
age1, hasSet1 := m["jimo"]
fmt.Println(age, hasSet, age1, hasSet1) // 20 true 0 false
// 删除
delete(m, "hehe")
fmt.Println(m)
// 遍历
for k, v := range m {
fmt.Println(k, v)
}
}
结构体
注意大对象使用指针传参,而不是值传递
package main
import "fmt"
type Person struct {
name string
age int8
}
func main() {
var p Person
p.name = "jimo"
p.age = 18
fmt.Println(p)
growUp(&p)
fmt.Println(p) // 19
growUpFake(p)
fmt.Println(p) // 19
// 字面量赋值
hehe := Person{
name: "hehe", age: 20,
}
fmt.Println(hehe)
}
func growUpFake(u Person) {
u.age += 1
}
func growUp(u *Person) {
u.age += 1
}
自定义基本类型
让基本类型变得有含义
package main
type KM float32
type M float32
func main() {
println(KM(1), M(1000))
dist := KM(1.1)
dist += toKM(M(2345)) // 可以做计算
println(dist)
}
func toKM(m M) KM {
return KM(m / 1000)
}
方法和函数
不过是一丘之貉
package main
type KM float32
type M float32
func main() {
m := M(123)
println(m.toKM())
}
func (m M) toKM() KM {
return KM(m / 1000)
}
Getter和Setter方法
注意使用指针作为参数
package main
import (
"errors"
"fmt"
"log"
"strconv"
)
type Person struct {
name string
age int8
}
func (p *Person) SetName(name string) {
p.name = name
}
func (p *Person) SetAge(age int8) error {
if age <= 0 {
return errors.New("不合法的年龄:" + strconv.Itoa(int(age)))
}
p.age = age
return nil
}
func (p *Person) Age() int8 {
return p.age
}
func main() {
p := Person{}
p.SetAge(18)
fmt.Println(p.Age())
err := p.SetAge(-1)
if err != nil {
log.Fatal(err)
}
fmt.Println(p)
}
接口与类型断言
go的接口实现居然是通过方法名来匹配的
package main
import "fmt"
type Animal interface {
Run()
}
type Dog struct {
}
// Run 通过方法继承
func (d Dog) Run() {
println("小狗跑了")
}
type Cat struct {
}
func (c Cat) Run() {
println("小猫跑了")
}
type Student struct{}
func main() {
animalRun(Dog{})
animalRun(Cat{})
// 接口类型断言
var a Animal = Dog{}
d, ok := a.(Dog)
fmt.Println(d, ok)
//s, ok := a.(Student)
//println(s, ok)
}
func animalRun(a Animal) {
a.Run()
}
那空接口怎么实现?
不用实现,所有的类都是其实例
package main
import (
"fmt"
)
// 空接口
type nothing interface {
}
type Person struct {
name string
age int8
}
func acceptAnything(a nothing) {
fmt.Println(a)
p, ok := a.(Person)
if ok {
fmt.Println("is Person: " + p.name)
}
}
func main() {
acceptAnything(Person{
name: "寂寞",
age: 18,
})
acceptAnything(1.2)
acceptAnything(1)
acceptAnything("hehe")
}
error接口
气接口定义为:
type error interface {
Error() string
}
package main
import "fmt"
type MyError string
func (e MyError) Error() string {
return string(e)
}
func main() {
var err error
err = MyError("我的错误实现")
fmt.Println(err)
}
Stringer接口:重写toString方法
type Stringer interface {
String() string
}
package main
import (
"fmt"
"strconv"
)
type Person struct {
name string
age int8
}
func (p Person) String以上是关于不到1000行,Go语言就算入门了吧的主要内容,如果未能解决你的问题,请参考以下文章