• go官网教程A Tour of Go


    http://tour.golang.org/#1

    中文版:http://go-tour-cn.appsp0t.com/#4

    package main

    import (
    "fmt"
    "math"
    )

    func main() {
    fmt.Println("Happy", math.Pi, "Day")
    }

    每个 Go 程序都是由包组成的。

    程序运行的入口从包的 main方法。

    这个程序使用并导入了包 "fmt" 和 "math"

    按惯例,包名与导入路径的最后一个目录一致

    这个代码用圆括号组合了导入,这是“factored”(分解因子)式导入声明。同样可以编写多个导入语句,例如:

            import "fmt"
            import "math"
            

    不过通常都会用 factored 格式来使代码工整。

    在导入了一个包之后,就可以用其导出的名称来调用它。

    Go 中,首字母大写的名称是被导出的。

    Foo 和 FOO 都是被导出的名称。 名称 foo 是不会被导出的。

    执行代码。然后将 math.pi 改为 math.Pi 再试着执行一下。

    package main
    
    import "fmt"
    
    func add(x int, y int) int {
        return x + y
    }
    
    func main() {
        fmt.Println(add(42, 13))
    }

    函数可以有零个或多个参数。

    在这个例子中,add 有两个 int 类型的参数。

    注意类型声明在变量名之后。(个人认为这个可以理解)

    (参考这篇关于 Go 语法定义的文章了解类型以这种形式出现的原因。)

    func swap(x, y string) (string, string) {
        return y, x
    }
    
    func main() {
        a, b := swap("hello", "world")
        fmt.Println(a, b)
    }

    函数可以返回任意数量的返回值。

    这个函数返回了两个字符串。

    func split(sum int) (x, y int) {
        x = sum * 4/9
        y = sum - x
        return
    }
    
    func main() {
        fmt.Println(split(17))
    }

    Functions take parameters. In Go, functions can return multiple "result parameters", not just a single value. They can be named and act just like variables.

    If the result parameters are named, a return statement without arguments returns the current values of the results.

    函数有参数。在 Go 中,函数可以返回多个“结果参数”,而不仅仅是一个值。它们可以像变量那样被命名和使用。

    如果命名了返回值的参数,一个没有参数的 return 语句,会将当前的值作为返回值返回。

    Var:

    var x, y, z int
    var c, python, java bool
    
    func main() {
        fmt.Println(x, y, z, c, python, java)
    }
     

    var 语句声明了一个变量的列表;跟函数的参数列表一样,类型声明在最后面。

    0 0 0 false false false
    var x, y, z int = 1, 2, 3
    var c, python, java = true, false, "no!"
    
    func main() {
        fmt.Println(x, y, z, c, python, java)
    }

    变量声明时可以包含初始值,每个变量对应一个。

    如果初始值是存在的,则可以省略类型声明;变量将从初始值中获得类型

    func main() {
        var x, y, z int = 1, 2, 3
        c, python, java := true, false, "no!"
    
        fmt.Println(x, y, z, c, python, java)
    }

    在一个函数里面,短赋值语句:= 可以用于替代 var 的隐式类型声明。

    := 结构不能使用在函数外,函数外的每个语法块都必须以关键字开始。)

    Constant:

    const Pi = 3.14
    
    func main() {
        const World = "世界"
        fmt.Println("Hello", World)
        fmt.Println("Happy", Pi, "Day")
    
        const Truth = true
        fmt.Println("Go rules?", Truth)
    }

    Constants are declared like variables, but with the const keyword.

    Constants can be character, string, boolean, or numeric values.

    注意这个Println。

    数值常量:

    const (
        Big = 1<<100
        Small = Big>>99
    )
    
    func needInt(x int) int { return x*10 + 1 }
    func needFloat(x float64) float64 {
        return x*0.1
    }
    
    func main() {
        fmt.Println(needInt(Small))
        fmt.Println(needFloat(Small))
        fmt.Println(needFloat(Big))
    }

    数值常量是高精度的

    一个未指定类型的常量由上下文来决定其类型。

    也尝试一下输出 needInt(Big)吧 溢出

    For:

    func main() {
        sum := 0
        for i := 0; i < 10; i++ {
            sum += i
        }
        fmt.Println(sum)
    }

    Go 只有一种循环结构,for 循环。

    基本的 for 循环看起来跟 C 或者 Java 中做的一样,除了没有了 ( ) 之外(甚至强制不能使用它们),而 { } 是必须的

    func main() {
        sum := 1
        for ; sum < 1000; {
            sum += sum
        }
        fmt.Println(sum)
    }

    As in C or Java, you can leave the pre and post statements empty.

    跟 C 或者 Java 中一样,前置、后置条件可以为空。

    func main() {
        sum := 1
        for sum < 1000 {
            sum += sum
        }
        fmt.Println(sum)
    }

    基于这一点,你也可以省略分号: C 的 while 循环在 Go 中也是用 for 实现

    func main() {
        for ; ; {
        }
    }

    如果省略了循环条件,它会一直循环下去(译者:死循环或无限循环)。

    func main() {
        for {
        }
    }

    为了避免累赘,分号也可以省略,这样一个无限循环可以被简洁地表达。

    if:

    import (
        "fmt"
        "math"
    )
    
    func pow(x, n, lim float64) float64 {
        if v := math.Pow(x, n); v < lim {
            return v
        } else {
            fmt.Printf("%g >= %g
    ", v, lim)
        }
        // can't use v here, though
        return lim
    }
    
    func main() {
        fmt.Println(
            pow(3, 2, 10),
            pow(3, 3, 20),
        )
    }

    在 if 的简短声明处定义的变量同样可以在对应的 else 块中使用。这点要特别注意。

    Go 的基本类型有

    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

    Structs

    struct is a collection of fields.

    (And a type declaration does what you'd expect.)

    一个结构体(struct)就是一个成员变量的集合。

    (而 type 定义跟其字面意思相符。)

    type Vertex struct {
        X int
        Y int
    }
    
    func main() {
        fmt.Println(Vertex{1, 2})
    }

    Struct Fields(结构体成员变量)使用点号来访问。

    func main(){
        v :=Vertex{1,2}
        v.X=4
        fmt.Println(v.X)
    }

    Pointers

    Go has pointers, but no pointer arithmetic.

    Struct fields can be accessed through a struct pointer. The indirection through the pointer is transparent.

    Go 有指针,但是没有指针运算。

    结构体成员变量可以通过结构体指针来访问。通过指针的间接访问也是透明的

    type Vertex struct{
        X int
        Y int
    }
    func main(){
        p := Vertex{1,2}
        q :=&p
        q.X=1e9
        fmt.Println(p)
    }

    输出:{1000000000 2}

    说明可以直接输出结构体。

    Struct Literals

    Struct Literals(结构体文法)表示通过结构体成员变量的值作为列表来新分配一个结构体。

    使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)

    特殊的前缀 & 构造了指向结构体文法的指针。


    Struct Literals

    A struct literal denotes a newly allocated struct value by listing the values of its fields.

    You can list just a subset of fields by using the Name: syntax. (And the order of named fields is irrelevant.)

    The special prefix & constructs a pointer to a struct literal.

    type Vertex struct {
        X, Y int
    }
    
    var (
        p = Vertex{1, 2}  // has type Vertex
        q = &Vertex{1, 2} // has type *Vertex
        r = Vertex{X: 1}  // Y:0 is implicit
        s = Vertex{}      // X:0 and Y:0
    )
    
    func main() {
        fmt.Println(p, q, r, s)
    }
    {1 2} &{1 2} {1 0} {0 0}

    new 函数

     

    表达式 new(T) 分配了一个零初始化的 T 值,并返回指向它的指针。(感觉这个语法有点奇怪,()里面为类型,怎么初始化呢?

    var t *T = new(T)

    t := new(T)

    The new function

    The expression new(T) allocates a zeroed T value and returns a pointer to it.

    var t *T = new(T)

    or

    t := new(T)
    type Vertex struct {
        X, Y int
    }
    
    func main() {
        v := new(Vertex)
        fmt.Println(v)
        v.X, v.Y = 11, 9
        fmt.Println(v)
    }

    Map

     

    map 映射键到值。

    map 必须用 make 来创建(不是 new;一个值为 nil 的 map 是空的,并且不能赋值。


    Maps

    A map maps keys to values.

    Maps must be created with make (not new) before use; the nil map is empty and cannot be assigned to.

    type Vertex struct {
        Lat, Long float64
    }
    
    var m map[string]Vertex
    
    func main() {
        m = make(map[string]Vertex)
        m["Bell Labs"] = Vertex{
            40.68433, 74.39967,
        }
        fmt.Println(m["Bell Labs"])
    }

    map literals(map 的文法)跟struct literals(结构体文法)相似,但是键是必须的。


    Maps

    Map literals are like struct literals, but the keys are required.

    type Vertex struct {
        Lat, Long float64
    }
    
    var m = map[string]Vertex{
        "Bell Labs": Vertex{
            40.68433, -74.39967,
        },
        "Google": Vertex{
            37.42202, -122.08408,
        },
    }
    
    func main() {
        fmt.Println(m)
    }
    map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

    Map

     

    如果顶层类型只有类型名的话,可以在文法的元素中省略键名。


    Maps

    If the top-level type is just a type name, you can omit it from the elements of the literal.

    type Vertex struct {
        Lat, Long float64
    }
    
    var m = map[string]Vertex{
        "Bell Labs": {40.68433, -74.39967},
        "Google":    {37.42202, -122.08408},
    }
    
    func main() {
        fmt.Println(m)
    }

    Insert or update an element in map m:

    m[key] = elem

    Retrieve an element:

    elem = m[key]

    Delete an element:

    delete(m, key)

    Test that a key is present with a two-value assignment:

    elem, ok = m[key]

    If key is in mok is true. If not, ok is false and elem is the zero value for the map's element type.

    Similarly, when reading from a map if the key is not present the result is the zero value for the map's element type.

    func main() {
        m := make(map[string]int)
    
        m["Answer"] = 42
        fmt.Println("The value:", m["Answer"])
    
        m["Answer"] = 48
        fmt.Println("The value:", m["Answer"])
    
        delete(m, "Answer")
        fmt.Println("The value:", m["Answer"])
    
        v, ok := m["Answer"]
        fmt.Println("The value:", v, "Present?", ok)
    }

    Slice

     

    slice 指向数组的值,并且同时包含了长度信息。

    []T 是一个元素类型为 T 的 slice。


    Slices

    A slice points to an array of values and also includes a length.

    []T is a slice with elements of type T. (java是T【】)

    func main() {
        p := []int{2, 3, 5, 7, 11, 13}
        fmt.Println("p ==", p)
    
        for i := 0; i < len(p); i++ {
            fmt.Printf("p[%d] == %d
    ",
                i, p[i])
        }
    }

    slice 可以重新切片,创建一个新的 slice 值指向相同的数组。

    表达式

    s[lo:hi]

    表示从 lo 到 hi-1 的 slice 元素,含有两端。 因此

    s[lo:lo]

    是空的,而

    s[lo:lo+1]

    有一个元素。

    func main() {
        p := []int{2, 3, 5, 7, 11, 13}
        fmt.Println("p ==", p)
        fmt.Println("p[1:4] ==", p[1:4])
    
        // missing low index implies 0
        fmt.Println("p[:3] ==", p[:3])
    
        // missing high index implies len(s)
        fmt.Println("p[4:] ==", p[4:])
    }

    跟python一样。

    slice 由函数 make 创建。这会分配一个零长度的数组并且返回一个 slice 指向这个数组:

    a := make([]int, 5)  // len(a)=5
            

    slice 有长度和容量。slice 的容量是底层数组可以增长的最大长度。

    为了指定容量,可传递第三个参数到 make

    b := make([]int, 0, 5)
    // len(b)=0, cap(b)=5
            

    slice 可以通过“重新切片”来扩容(增加容量):

    b = b[:cap(b)] // len(b)=5, cap(b)=5
    b = b[1:]      // len(b)=4, cap(b)=4

    func main() {
        a := make([]int, 5)
        printSlice("a", a)
        b := make([]int, 0, 5)
        printSlice("b", b)
        c := b[:2]
        printSlice("c", c)
        d := c[2:5]
        printSlice("d", d)
        
        e :=make([]int,10)
        printSlice("e",e);
    }

    打印slice通过printSlice

    function

     函数也是值。

    func main() {
    hypot := func(x, y float64) float64 {
    return math.Sqrt(x*x + y*y)
    }

    fmt.Println(hypot(3, 4))
    }

    函数

     
    func adder() func(int) int {
        sum := 0
        return func(x int) int {
            sum += x
            return sum
        }
    }
    
    func main() {
        pos, neg := adder(), adder()
        for i := 0; i < 10; i++ {
            fmt.Println(
                pos(i),
                neg(-2*i),
            )
        }
    }

    并且函数是完全闭包的。

    函数 adder 返回一个闭包。每个闭包被绑定到自己的 sum 变量上


    Functions

    And functions are full closures.

    The adder function returns a closure. Each closure is bound to its own sumvariable.

    Range

     

    可以将值赋值给 _ 来忽略键和值。

    如果只需要索引值,去掉“, value”的部分即可。


    Range

    You can skip the index or value by assigning to _.

    If you only want the index, drop the “, value” entirely.

        pow := make([]int, 10)
        for i := range pow {
            pow[i] = 1<<uint(i)
        }
        for _, value := range pow {
            fmt.Printf("%d
    ", value)

    Switch

     

    你可能已经猜到 switch 的形式了。

    case 语句匹配后会自动终止,除非用 fallthrough 语句作为结尾。

    import (
        "fmt"
        "runtime"
    )
    
    func main() {
        fmt.Print("Go runs on ")
        switch os := runtime.GOOS; os {
        case "darwin":
            fmt.Println("OS X.")
        case "linux":
            fmt.Println("Linux.")
        default:
            // freebsd, openbsd,
            // plan9, windows...
            fmt.Printf("%s.", os)
        }
    }

    没有条件的 switch 与 switch true 一样。

    这一构造使得可以用更清晰的形式来编写if-then-else。

    import (
        "fmt"
        "time"
    )
    
    func main() {
        t := time.Now()
        switch {
        case t.Hour() < 12:
            fmt.Println("Good morning!")
        case t.Hour() < 17:
            fmt.Println("Good afternoon.")
        default:
            fmt.Println("Good evening.")
        }
    }

    方法

     

    Go 没有类。然而,仍然可以在结构体类型上定义方法。

    方法接收者出现在 func 关键字和方法名之间的参数中。

    import (
        "fmt"
        "math"
    )
    
    type Vertex struct {
        X, Y float64
    }
    
    func (v *Vertex) Abs() float64 {
        return math.Sqrt(v.X*v.X + v.Y*v.Y)
    }
    
    func main() {
        v := &Vertex{3, 4}
        fmt.Println(v.Abs())
    }

    事实上,可以对包中的任意类型定义任意方法,而不仅仅是结构体。

    不能对来自其他包的类型或基础类型定义方法。

    type MyFloat float64
    
    func (f MyFloat) Abs() float64 {
        if f < 0 {
            return float64(-f)
        }
        return float64(f)
    }
    
    func main() {
        f := MyFloat(-math.Sqrt2)
        fmt.Println(f.Abs())
    }

    接收者为指针的方法

    方法可以与命名类型或命名类型的指针关联。

    刚刚看到的两个 Abs 方法。一个是在 *Vertex 指针类型上,而另一个在MyFloat 值类型上。

    有两个原因需要使用指针接收者。首先避免在每个方法调用中拷贝值(如果值类型是大的结构体的话会更有效率)。其次,方法可以修改接收者指向的值。

    尝试修改 Abs 的定义,同时 Scale 方法使用 Vertex 代替 *Vertex 作为接收者。

    当 v 是 Vertex 的时候 Scale 方法没有任何作用。Scale 修改 v。当 v 是一个值(非指针),方法看到的是 Vertex 的副本,并且无法修改原始值。

    Abs 的工作方式是一样的。只不过,仅仅读取 v。所以读取的是原始值(通过指针)还是那个值的副本并没有关系。

    type Vertex struct {
        X, Y float64
    }
    
    func (v *Vertex) Scale(f float64) {
        v.X = v.X * f
        v.Y = v.Y * f
    }
    
    func (v *Vertex) Abs() float64 {
        return math.Sqrt(v.X*v.X + v.Y*v.Y)
    }
    
    func main() {
        v := &Vertex{3, 4}
        v.Scale(5)
        fmt.Println(v, v.Abs())
    }
    &{15 20} 25
    去掉指针值没有变化。

    接口

     

    接口类型是由一组方法定义的。

    接口类型的值可以容纳实现这些方法的任何值。


    Interfaces

    An interface type is defined by a set of methods.

    A value of interface type can hold any value that implements those methods.

     
    type Abser interface {
        Abs() float64
    }
    
    func main() {
        var a Abser
        f := MyFloat(-math.Sqrt2)
        v := Vertex{3, 4}
    
        a = f  // a MyFloat implements Abser
        a = &v // a *Vertex implements Abser
        a = v  // a Vertex, does NOT
               // implement Abser
    
        fmt.Println(a.Abs())
    }
    
    type MyFloat float64
    
    func (f MyFloat) Abs() float64 {
        if f < 0 {
            return float64(-f)
        }
        return float64(f)
    }
    
    type Vertex struct {
        X, Y float64
    }
    
    func (v *Vertex) Abs() float64 {
        return math.Sqrt(v.X*v.X + v.Y*v.Y)
    }

    一种类型通过实现那些方法来实现接口。

    没有显式声明的必要。

    隐式接口解藕了实现接口的包和定义接口的包:互不依赖。

    也鼓励明确的接口定义,因为这样就无需找到每一个实现,并对其加上新的接口名称。

    Package io 定义了 Reader 和 Writer;但不是一定要这么做。

    import (
        "fmt"
        "os"
    )
    
    type Reader interface {
        Read(b []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(b []byte) (n int, err error)
    }
    
    type ReadWriter interface {
        Reader
        Writer
    }
    
    func main() {
        var w Writer
    
        // os.Stdout implements Writer
        w = os.Stdout
    
        fmt.Fprintf(w, "hello, writer
    ")
    }

  • 相关阅读:
    torch.optim.SGD()各参数的解释
    pytorch中y.data.norm()的含义
    sklearn分类模块
    python处理nii文件
    cvpr2019_Unsupervised Person Re-identification by Soft Multilabel Learning
    attention机制
    contrastive loss
    pytorch扩展——如何自定义前向和后向传播
    python | 实现多行向量(matrix)两两计算余弦距离、欧几里德距离
    判定是否过拟合、欠拟合的一种方式
  • 原文地址:https://www.cnblogs.com/youxin/p/3595238.html
Copyright © 2020-2023  润新知