社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
package main
import "fmt"
func main() {
fmt.Println("Hello, 世界")
}
命令行
$ go run helloworld.go
$ go build helloworld.go
Go语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。
Go语言在代码格式上采取了很强硬的态度。gofmt工具把代码格式化为标准格式。
很多文本编辑器都可以配置为保存文件时自动执行gofmt,这样你的源代码总会被恰当地格式化。还有个相关的工具,goimports,可以根据代码需要, 自动地添加或删除import声明。
$ go get golang.org/x/tools/cmd/goimports
os.Args变量是一个字符串(string)的切片(slice)
用s[i]访问单个元素,用s[m:n]获取子序列
序列的元素数目为len(s)
Go言里也采用左闭右开形式,比如s[m:n]这个切片,0 ≤ m ≤ n ≤ len(s),包含n-m个元素。
os.Args[1:len(os.Args)]切片中。如果省略切片表达式的m或n,会默认传入0或len(s),因此前面的切片可以简写成os.Args[1:]。
var 变量名字 类型 = 表达式
var i, j, k int // int, int, int
var b, f, s = true, 2.3, "four" // bool, float64, string
in, err := os.Open(infile)
// ...
out, err := os.Create(outfile)
p := new(int)
用new新建一个int型指针count[x] = count[x] * scale // 数组、slice或map的元素赋值
x, y = y, x
a[i], a[j] = a[j], a[i]
_, ok = x.(T) // 只检测类型,忽略具体值```
###2.5类型
1. 类型重定义:```type 类型名字 底层类型```
2. 类型转换:```类型名字(参数)```
3. 只有底层类型相同,或者底层类型可以互相转换的类,才可以做类型转换。
4. 类型不同(就算底层类型相同)也不能做比较运算
5. 下面的声明语句,Celsius类型的参数c出现在了函数名的前面,表示声明的是Celsius类型的一个名叫String的方法,该方法返回该类型对象c带着°C温度单位的字符串:
```func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }```
<div class="se-preview-section-delimiter"></div>
###2.6包和文件
1. 在Go语言中,一个简单的规则是:如果一个名字是大写字母开头的,那么该名字是导出的。也就是说别的包,只要引用了改包就可以使用的参数。
``fmt.Printf("Brrrr! %vn", tempconv.AbsoluteZeroC) // "Brrrr! -273.15°C"``
2. 包内函数的使用:```fmt.Println(tempconv.CToF(tempconv.BoilingC)) // "212°F"```,注意只有引用包的文件可以调用函数。
3. 在Go语言程序中,每个包都有一个全局唯一的导入路径。导入语句中类似"gopl.io/ch2/tempconv"的字符串对应包的导入路径。
<div class="se-preview-section-delimiter"></div>
```go
import(
"gopl.io/ch2/tempconv"
)
func init() {/*...*/}
//使用init初始化
package popcount
// pc[i] is the population count of i.
var pc [256]byte
func init() {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
}
//或者使用匿名函数初始化
// pc[i] is the population count of i.
var pc [256]byte = func() (pc [256]byte) {
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
return
}()
func main() {
x := "hello!"
for i := 0; i < len(x); i++ {
x := x[i]
if x != '!' {
x := x + 'A' - 'a'
fmt.Printf("%c", x) // "HELLO" (one letter per iteration)
}
}
}
if x := f(); x == 0 {
fmt.Println(x)
} else if y := g(x); x == y {
fmt.Println(x, y)
} else {
fmt.Println(x, y)
}
fmt.Println(x, y) // compile error: x and y are not visible here
if f, err := os.Open(fname); err != nil { // compile error: unused: f
return err
}
f.ReadByte() // compile error: undefined f
f.Close() // compile error: undefined f
// "program" in Japanese katakana
s := "プログラム"
fmt.Printf("% xn", s) // "e3 83 97 e3 83 ad e3 82 b0 e3 83 a9 e3 83 a0"
r := []rune(s)
fmt.Printf("%xn", r) // "[30d7 30ed 30b0 30e9 30e0]"
如果是将一个[]rune类型的Unicode字符slice或数组转为string,则对它们进行UTF8编码:
fmt.Println(string(r)) // "プログラム"
fmt.Println(string(65)) // "A", not "65"
fmt.Println(string(0x4eac)) // "京"
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // "1 1 2 2"
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
var a [3]int // array of 3 integers
fmt.Println(a[0]) // print the first element
fmt.Println(a[len(a)-1]) // print the last element, a[2]
fmt.Println(summer[:20]) // panic: out of range
endlessSummer := summer[:5] // extend a slice (within capacity)
fmt.Println(endlessSummer) // "[June July August September October]"
make([]T, len)
make([]T, len, cap) // same as make([]T, cap)[:len]
var runes []rune
for _, r := range "Hello, 世界" {
runes = append(runes, r)
}
fmt.Printf("%qn", runes) // "['H' 'e' 'l' 'l' 'o' ',' ' ' '世' '界']"
runes = append(runes, r)
stack = append(stack, v) // push v
top := stack[len(stack)-1] // top of stack
stack = stack[:len(stack)-1] // pop
ages := make(map[string]int) // mapping from strings to ints
names := make([]string, 0, len(ages))
age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0. */ }
map[string]bool
type Employee struct {
ID int
Name, Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
type tree struct {
value int
left, right *tree
}
// Sort sorts values in place.
func Sort(values []int) {
var root *tree
for _, v := range values {
root = add(root, v)
}
appendValues(values[:0], root)
}
// appendValues appends the elements of t to values in order
// and returns the resulting slice.
func appendValues(values []int, t *tree) []int {
if t != nil {
values = appendValues(values, t.left)
values = append(values, t.value)
values = appendValues(values, t.right)
}
return values
}
func add(t *tree, value int) *tree {
if t == nil {
// Equivalent to return &tree{value: value}.
t = new(tree)
t.value = value
return t
}
if value < t.value {
t.left = add(t.left, value)
} else {
t.right = add(t.right, value)
}
return t
}
type Point struct{ X, Y int }
p := Point{1, 2}
p := Point{a:1, b:2}
pp := &Point{1, 2}//这里pp是指针
pp := new(Point)
*pp = Point{1, 2}
type Circle struct {
Point
Radius int
}
type Wheel struct {
Circle
Spokes int
}
var w Wheel
w.X = 8 // equivalent to w.Circle.Point.X = 8
w.Y = 8 // equivalent to w.Circle.Point.Y = 8
w.Radius = 5 // equivalent to w.Circle.Radius = 5
w.Spokes = 20
w = Wheel{8, 8, 5, 20} // compile error: unknown fields
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
/ CountWordsAndImages does an HTTP GET request for the HTML
// document url and returns the number of words and images in it.
func CountWordsAndImages(url string) (words, images int, err error) {
resp, err := http.Get(url)
if err != nil {
return
}
doc, err := html.Parse(resp.Body)
resp.Body.Close()
if err != nil {
err = fmt.Errorf("parsing HTML: %s", err)
return
}
words, images = countWordsAndImages(doc)
return
}
func countWordsAndImages(n *html.Node) (words, images int) { /* ... */ }
return nil, fmt.Errorf("parsing %s as HTML: %v", url,err)
// WaitForServer attempts to contact the server of a URL.
// It tries for one minute using exponential back-off.
// It reports an error if all attempts fail.
func WaitForServer(url string) error {
const timeout = 1 * time.Minute
deadline := time.Now().Add(timeout)
for tries := 0; time.Now().Before(deadline); tries++ {
_, err := http.Head(url)
if err == nil {
return nil // success
}
log.Printf("server not responding (%s);retrying…", err)
time.Sleep(time.Second << uint(tries)) // exponential back-off
}
return fmt.Errorf("server %s failed to respond after %s", url, timeout)
}
3) 输出错误信息并结束程序。
4)可以通过log包提供函数,或者标准错误流输出错误信息。
if err := Ping(); err != nil {
log.Printf("ping failed: %v; networking disabled",err)
}
if err := Ping(); err != nil {
fmt.Fprintf(os.Stderr, "ping failed: %v; networking disabledn", err)
}
5) 直接忽略
// squares返回一个匿名函数。
// 该匿名函数每次被调用时都会返回下一个数的平方。
func squares() func() int {
var x int
return func() int {
x++
return x * x
}
}
func main() {
f := squares()
fmt.Println(f()) // "1"
fmt.Println(f()) // "4"
fmt.Println(f()) // "9"
fmt.Println(f()) // "16"
}
var visitAll func(items []string)//第一步声明
visitAll = func(items []string) {//第二步定义
...}
}
func sum(vals...int) int {
total := 0
for _, val := range vals {
total += val
}
return total
}
values := []int{1, 2, 3, 4}
fmt.Println(sum(values...)) // "10"
defer resp.Body.Close()
func bigSlowOperation() {
defer trace("bigSlowOperation")() // don't forget the
extra parentheses
// ...lots of work…
time.Sleep(10 * time.Second) // simulate slow
operation by sleeping
}
func trace(msg string) func() {
start := time.Now()
log.Printf("enter %s", msg)
return func() {
log.Printf("exit %s (%s)", msg,time.Since(start))
}
}
$ go build gopl.io/ch5/trace
$ ./trace
2015/11/18 09:53:26 enter bigSlowOperation
2015/11/18 09:53:36 exit bigSlowOperation (10.000589217s)
func double(x int) int {
return x + x
}
panic(err)
// soleTitle returns the text of the first non-empty title element
// in doc, and an error if there was not exactly one.
func soleTitle(doc *html.Node) (title string, err error) {
type bailout struct{}
defer func() {
switch p := recover(); p {
case nil: // no panic
case bailout{}: // "expected" panic
err = fmt.Errorf("multiple title elements")
default:
panic(p) // unexpected panic; carry on panicking
}
}()
// Bail out of recursion if we find more than one nonempty title.
forEachNode(doc, func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "title" &&
n.FirstChild != nil {
if title != "" {
panic(bailout{}) // multiple titleelements
}
title = n.FirstChild.Data
}
}, nil)
if title == "" {
return "", fmt.Errorf("no title element")
}
return title, nil
}
type Point struct{ X, Y float64 }
// same thing, but as a method of the Point type
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
type P *int
func (P) f() { /* ... */ } // compile error: invalid receiver type
(&p).ScaleBy(2)
可以这么表达p.ScaleBy(2)
)但是我们不能通过一个无法取到地址的接收器来调用指针方法,比如临时变量的内存地址就无法获取得到:Point{1, 2}.ScaleBy(2) // compile error: can't take address of Point literal
pptr.Distance(q)
(*pptr).Distance(q)
import "image/color"
type Point struct{ X, Y float64 }
type ColoredPoint struct {
Point
Color color.RGBA
}
p.Distance(q.Point)
调用,这样是错的p.Distance(q)
, 但是可以重新针对ColoredPoint定义Distance方法。type ColoredPoint struct {
*Point
Color color.RGBA
}
p := ColoredPoint{&Point{1, 1}, red}
q := ColoredPoint{&Point{5, 4}, blue}
fmt.Println(p.Distance(*q.Point)) // "5"
q.Point = p.Point // p and q now share the same Point
p.ScaleBy(2)
fmt.Println(*p.Point, *q.Point) // "{2 2} {2 2}"
var cache = struct {
sync.Mutex
mapping map[string]string
}{
mapping: make(map[string]string),
}
distanceFromP := p.Distance // method value
fmt.Println(distanceFromP(q)) // "5"
p := Point{1, 2}
q := Point{4, 6}
distance := Point.Distance // method expression
fmt.Println(distance(p, q)) // "5"
fmt.Printf("%Tn", distance) // "func(Point, Point) float64"
scale := (*Point).ScaleBy
scale(&p, 2)
fmt.Println(p) // "{2 4}"
fmt.Printf("%Tn", scale) // "func(*Point, float64)"
// 译注:这个Distance实际上是指定了Point对象为接收器的一个方法func (p Point) Distance(),
// 但通过Point.Distance得到的函数需要比实际的Distance方法多一个参数,
// 即其需要用第一个额外参数指定接收器,后面排列Distance方法的参数。
// 看起来本书中函数和方法的区别是指有没有接收器,而不像其他语言那样是指有没有返回值。
ype Point struct{ X, Y float64 }
func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }
type Path []Point
func (path Path) TranslateBy(offset Point, add bool) {
var op func(p, q Point) Point
if add {
op = Point.Add
} else {
op = Point.Sub
}
for i := range path {
// Call either path[i].Add(offset) or path[i].Sub(offset).
path[i] = op(path[i], offset)
}
}
package io
type Reader interface {
Read(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
type ReadWriter interface {
Reader
Writer
}
var _ = IntSet{}.String()
这种方式寻址的(String()是接口实现的方法),报错compile error: String requires *IntSet receiver
但是可以用变量调用var s IntSet;var _ = s.String()
f := 实现接口类型{value参数};flag.CommandLine.Var(&f, name, usage)
加入名两行参数type Value interface {
String() string
Set(string) error
}
flag.Parse()
打印命令行参数var w io.Writer
: w = os.Stdout
var buf *bytes.Buffer
这个接口值,指向的内容不是nil,但是参数value是nil,所以在执行有些参数不能为nil的方法时也会报错的。尽量不要用这种方式。 package sort
type Interface interface {
Len() int
Less(i, j int) bool // i, j are indices of sequence elements
Swap(i, j int)
}
举例:
type StringSlice []string
func (p StringSlice) Len() int { return len(p) }
func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
sort.Sort(StringSlice(names))//执行排序
package sort
type reverse struct{ Interface } // that is, sort.Interface
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }
func Reverse(data Interface) Interface { return reverse{data} }
sort.Sort(sort.Reverse(接口值))
func main() {
db := database{"shoes": 50, "socks": 5}
log.Fatal(http.ListenAndServe("localhost:8000", db))
}
type dollars float32
func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }
type database map[string]dollars
func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/list":
for item, price := range db {
fmt.Fprintf(w, "%s: %sn", item, price)
}
case "/price":
item := req.URL.Query().Get("item")
price, ok := db[item]
if !ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "no such item: %qn", item)
return
}
fmt.Fprintf(w, "%sn", price)
default:
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "no such page: %sn", req.URL)
}
}
func main() {
db := database{"shoes": 50, "socks": 5}
mux := http.NewServeMux()
mux.Handle("/list", http.HandlerFunc(db.list))
mux.Handle("/price", http.HandlerFunc(db.price))
log.Fatal(http.ListenAndServe("localhost:8000", mux))
}
type database map[string]dollars
func (db database) list(w http.ResponseWriter, req *http.Request) {
for item, price := range db {
fmt.Fprintf(w, "%s: %sn", item, price)
}
}
func (db database) price(w http.ResponseWriter, req *http.Request) {
item := req.URL.Query().Get("item")
price, ok := db[item]
if !ok {
w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintf(w, "no such item: %qn", item)
return
}
fmt.Fprintf(w, "%sn", price)
}
中间db.list和db.price都是方法值,语句http.HandlerFunc(db.list)是一个转换而非一个函数调用,因为http.HandlerFunc是一个类型
package http
type HandlerFunc func(w ResponseWriter, r *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
注意这里HandlerFunc类型是一个函数,这种
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!