区块链研发工程师、Go服务器端/游戏软件工程师、Golang分布式/云计算软件工程师
新建一个文件夹ch1,创建文件helloworld.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
cmd运行 go run helloworld.go
或者 go build helloworld.go
生成helloworld.exe,然后运行exe亦可
其中main包用来定义一个独立的可执行程序,而不是库;同时main函数是程序开始执行的地方
在ch1下创建文件echo1.go
package main
//导入多个包可以选择用()标识列表,gofmt工具会按字母顺序进行排序
import (
"fmt"
"os"
)
func main() {
//默认string变量是空字符串""
var s, sep string
//这里的Args代表的是从命令行获取的参数列表,i从1开始是因为Args[0]是命令本身的名字
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}
在cmd输入go run echo1.go 参数1 参数2 参数...
输出结果为:参数1 参数2 参数...
第二种形式的for循环
package main
import (
"fmt"
"os"
)
func main() {
s, sep := "", ""
//使用range遍历Args会产生两个值:索引和索引对应元素;因为不需要索引,所以我们可以使用空标识符_来占位
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
fmt.Println(s)
}
因为前两种s += sep + arg的过程是不断创建新的string变量,不断进行垃圾回收,为了提高效率,我们可以使用工具类strings的Join函数
package main
import (
"fmt"
"os"
"strings"
)
func main() {
fmt.Println(strings.Join(os.Args[1:], " "))
}
控制台输入数据,并找出重复出现的部分
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
//利用内置函数make定义一个key为string,value为int的map
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
//忽略input.Err()中可能的错误
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
命令行ctrl+z
回车结束输入
可以在标准输入中读取,也可以从具体文件中读取
流式
模式读取输入
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
files := os.Args[1:]
if len(files) == 0 {
countLines(os.Stdin, counts)
} else {
for _, arg := range files {
f, err := os.Open(arg)
//err等于nil的时候,代表文件正常打开
if err != nil {
//Fprintf代表在标准错误流上输出一条信息,%v代表使用默认格式显示任意类型的值
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s", n, line)
}
}
}
func countLines(f *os.File, counts map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
counts[input.Text()]++
}
}
一次读取整个文件输入到大块内存,一次性地分割所有行,然后处理这些行
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
counts := make(map[string]int)
for _, filename := range os.Args[1:] {
//data存储的是ReadFile函数返回的可以转化成字符串的字节slice,可以被strings.Split函数分割
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
continue
}
for _, line := range strings.Split(string(data), "\n") {
counts[line]++
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
了解即可
package main
import (
"image"
"image/color"
"image/gif"
"io"
"log"
"math"
"math/rand"
"net/http"
"os"
"time"
)
//定义画板颜色
var palette = []color.Color{color.White, color.Black}
const (
whiteIndex = 0 //画板中的第一种颜色
blackIndex = 1 //画板中的下一种颜色
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
if len(os.Args) > 1 && os.Args[1] == "web" {
handler := func(w http.ResponseWriter, r *http.Request) {
lissajous(w)
}
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
return
}
lissajous(os.Stdout)
}
func lissajous(out io.Writer) {
const (
cycles = 5 //完整的x振荡器变化的个数
res = 0.001 //角度分辨率
size = 100 //图像画布包含[-size .. +size]
nframes = 64 //动画中的帧数
delay = 8 //以10ms为单位的帧间延迟
)
freq := rand.Float64() * 3.0 //y振荡器的相对频率
anim := gif.GIF{LoopCount: nframes}
phase := 0.0 //phase difference
for i := 0; i < nframes; i++ {
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
img := image.NewPaletted(rect, palette)
for t := 0.0; t < cycles*2*math.Pi; t += res {
x := math.Sin(t)
y := math.Sin(t*freq + phase)
img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
}
phase += 0.1
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim) //注意:忽略编码错误
}
cmd输入go build lissajous
+lissajous >out.gif
可以得到out.gif文件,或者使用go run lissajous >out.gif
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
for _, url := range os.Args[1:] {
resp, err := http.Get(url)
if err != nil {
fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
os.Exit(1)
}
b, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
os.Exit(1)
}
fmt.Printf("%s", b)
}
}
go build fetch.go
+ fetch http://pop1.io
得到请求的页面
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"time"
)
func main() {
start := time.Now()
//make创建一个string类型的管道
ch := make(chan string)
for _, url := range os.Args[1:] {
go fetch(url, ch) //启动一个goroutine
}
for range os.Args[1:] {
fmt.Println(<-ch) //从通道ch接收
}
fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}
func fetch(url string, ch chan<- string) {
start := time.Now()
resp, err := http.Get(url)
if err != nil {
ch <- fmt.Sprint(err) //发送到通道ch
return
}
nbytes, err := io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close() //不要泄漏资源
if err != nil {
ch <- fmt.Sprintf("while reading %s: %v", url, err)
return
}
secs := time.Since(start).Seconds()
ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
}
go build fetchall.go
+ fetchall https://baidu.com https://google.cn
设计一个迷你回声服务器
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", handler) //回声请求调用处理程序
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
//处理程序回显请求URL r的路径部分
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.path = %q\n", r.URL.Path)
}
cmd输入go run server1.go
就会开启一个服务器
可以cmd访问也可以直接通过浏览器访问,浏览器访问在地址栏输入localhost:8000/hello
会输出URL.path = "/hello
在server1的基础上新增了统计访问次数的功能
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
//同步锁
var mu sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler) //回声请求调用处理程序
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
//处理程序回显请求URL r的路径部分
func handler(w http.ResponseWriter, r *http.Request) {
mu.Lock()
count++
mu.Unlock()
fmt.Fprintf(w, "URL.path = %q\n", r.URL.Path)
}
//counter显示目前为止调用的次数
func counter(w http.ResponseWriter, r *http.Request) {
mu.Lock()
fmt.Fprintf(w, "Count %d\n", count)
mu.Unlock()
}
if err := r.ParseForm();err != nil{
}
//等价于
err := r.Parseform()
if err != nil{
}
但是合并的语句更短且缩小了err变量的作用域。
switch coinflip(){
case "heads":
heads++
case "tails":
tails++
default:
fmt.Println("landed on edge!")
}
case语句不会像C语言那样从上到下贯穿执行(尽管有一个很少使用的fallthrough语句可以改写这个行为)
switch语句也可以不需要操作数,它就像一个case语句列表,每条case语句都是一个布尔表达式:
func Signum(x int) int{
switch{
case x > 0:
return +1
default:
return 0
case x M 0:
return 01
}
}
这种形式称为无标签
选择,等价于switch true
type声明给已有类型命名
type Point struct{
x, y int
}
var p Point
指针
方法和借口
包
注释:不能嵌套
使用go doc工具可以访问文档
go给我感觉是在吸取经验的同时又舍弃了好多内容,比如–i,指针加减。
目前来看语法看似不严谨实则要求非常统一。