import "fmt"
import
keyword is how we include code from other packages to use with our program. The fmt
package (shorthand for format) implements formatting for input and output.
func
followed by the name of the function (
main
in this case), a list of zero or more “parameters” surrounded by parentheses, an optional return type and a “body” which is surrounded by curly braces. 整个签名式的顺序类似于C++ lambda。
The Println
function does the real work in this program. You can find out more about it by typing the following in your terminal:
uint8
,
uint16
,
uint32
,
uint64
,
int8
,
int16
,
int32
and
int64.
byte
which is the same as
uint8
and
rune
which is the same as
int32
.
byte
data type is often used in the definition of other types. There are also 3 machine dependent integer types:
uint
,
int
and
uintptr
. They are machine dependent because their size depends on the type of architecture you are using.
float32
and
float64,
complex numbers (numbers with imaginary parts):
complex64
and
complex128
. Generally we should stick with
float64
when working with floating point numbers.
"Hello World"
or back ticks
`Hello World`
. 后者允许字符串里面出现多行,类似于python的"""。
Go's basic types are
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
fmt.Printf("%T %v %q")分别输出type, value, raw data.
其中,method可以写在不同的文件,但是必须与Class在同一个类中。【package使用Method/method表示exposure,但是class method不行。
func (obj Class) Method(para lit) returnType {
}
func (v *Vertex) Scale(f float64){}这里的pointer receiver表示可以更改属性值。但依然使用v.X访问属性,调用方式也是v.Scale()。但是如果Scale写为函数,必须使用&v传递参数给*Vertex,访问属性方法不变。
The first is so that the method can modify the value that its receiver points to.
The second is to avoid copying the value on each method call.
In general, all methods on a given type should have either value or pointer receivers, but not a mixture of both.
A type implements an interface by implementing its methods. 并不能显式声明implement某个interface。
目前能看到的interface的用法就是声明一个I类型的变量i,赋值为T类型,调用interface声明过的方法。
var i I = T{"hello"}
i.M()
目前没有看到interface接受过receiver参数。
假设
type I interface {
M()
}
func (t T) M() {
fmt.Println(t.S)
}
// 如果interface method接受T类型参数,传一个指针,可以接受;但是如果接受*T,不能使用T类型的obj调用这个method,因为interface类型。
i := T{"hello"}
i.M()
如果是普通class method,可以*T调用receiver T类型的method;可以T调用receiver *T的method。
但是如果interface method,不能使用T调用receiver *T的method,认为T does not implement I(M method has pointer receiver).
四种情况
*T调用receiver *T,应该是把*T当作一种类型
T调用receiver T,正常。
*T调用receiver T,不知道为啥。。
T调用receiver *T,失败;
type T struct {
S string
T int
B string
}
i = &T{"Hello", 2, "nihao"}
自定义类型初始化 i = T{para list},好像必须按声明顺序传值。此时i value= &{Hello 2 nihao}, type=*main.T
built-in类型 i = float64(2.3)
新定义一个指针的方式是i := &T{},即先创建一个obj然后取地址。
var t *T 此时t是指向nil的*T类型指针;
var t T 此时t是一个空object.
var i interface{}这样的话,i可以被赋值为任何类型【因为空interface对type没任何要求】,但是不能调用任何方法;
https://tour.golang.org/methods/15 type assertion
A type assertion provides access to an interface value's underlying concrete value.
t := i.(T)
This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t.
If i does not hold a T, the statement will trigger a panic.
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.
t, ok := i.(T)
If i holds a T, then t will be the underlying value and ok will be true.
If not, ok will be false and t will be the zero value of type T, and no panic occurs.
比如,
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok) // hello true
f, ok := i.(float64)
fmt.Println(f, ok) // 0 false
f = i.(float64) // panic
fmt.Println(f)
https://tour.golang.org/methods/16 type switch
A type switch is a construct that permits several type assertions in series.
A type switch is like a regular switch statement, but the cases in a type switch specify types (not values), and those values are compared against the type of the value held by the given interface value.
switch v := i.(type) { // 这里使用i.(type)而不是上面的i.(string)
case T:
// here v has type T 这里v是类型T
case S:
// here v has type S
default:
// no match; here v has the same type as i
}
byte->string: ret += strconv.Itoa(int(no))
fmt.Stringer是一个interface,定义了String()string{}接口;如果一个类重写了这个接口,在%v格式输出时候会输出返回值;
type T如果有func (t T)String() string {},在输出时候会自动调用,但receiver必须是T而不是*T。
同理,type error interface{ Error() string}接口
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string { // Error interface
return fmt.Sprintf("at %v, %s", // fmt.Sprintf和C类似
e.When, e.What)
}
func run() error { // 注意这里返回的是error,built-in class,返回值实际是*MyError类型的值。如果把return 和 Error()的receiver同时改为MyError类型,可以work
return &MyError{ // 返回一个
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
b := make([]byte, 8)
n, err := r.Read(b) // func (T) Read(b []byte) (n int, err error)
这里函数Read作为类成员函数,从T读bytes存入参数b,返回读的bytes数,和error msg(如果EOF,返回io.EOF)
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
channel是typed;这里的代码是向c发送两次,接收两次。
package main
import (
"fmt"
"time"
)
func buf(ch chan int) {
fmt.Println("start buffer")
ch <- 2
fmt.Println("end buffer")
}
func main() {
ch := make(chan int, 1)
ch <- 1
go buf(ch)
time.Sleep(100 * time.Millisecond)
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println("Main End")
}
goroutine如果main执行完退出,可能有些子goroutine的语句不执行,直接整个程序退出?
https://gobyexample.com/closing-channels
channel如果想标识end,
close(CHANNEL)和 val, ok := <- CHANNEL; if ok 搭配使用。
Go struct
https://golang.org/ref/spec#Struct_types