Go学习笔记一

变量、类型和关键字

完整的整数类型列表(符号和无符号)是

int8int16int32int64byteuint8uint16uint32uint64

混合用这些类型向变量赋值会引起编译器错误,例如下面的代码:

package main

func main() {
    var a int   //← 通用整数类型
    var b int32 //← 32 位整数类型
    a = 15
    b = a + a //← 混合这些类型是非法的 
              //cannot use a + a (type int) as type int32 in assignment
    println(b)
    b = b + 5 //← 5 是一个(未定义类型的)常量,所以这没问题
    println(b)
}

字符串

字符串在 Go 中是 UTF-8 的由双引号(”)包裹的字符序列。如果你使用单引号(’)则
表示一个字符(UTF-8 编码)——这种在 Go 中 不是 string。
一旦给变量赋值,字符串就不能修改了:在 Go 中字符串是不可变的。从 C 来的用户,
下面的情况在 Go 中是非法的。

var s string = "hello"
s[0] = 'c' //← 修改第一个字符为 ’c’ ,这会报错

在 Go 中实现这个,需要下面的方法:

package main 

import "fmt"

func main() {
    var s = "hello"
    var c = [] rune (s)//转换 s 为 rune 数组

    c[0] = 'c'//修改第一个字符为 ’c’

    var s2 = string (c)//创建 新的 字符串 s2 保存修改;

    fmt.Printf("%s\n", s2)

}

多行字符串

基于分号的置入,你需要小心使用多行字符串。如果这样写:

s := "Starting part"
+ "Ending part"

会被转换为:

s := "Starting part" ;
+ "Ending part" ;

这是错误的语法,应当这样写:

//正确的方式一:
s := "Starting part" +
"Ending part"

正确的方式二:
Go 就不会在错误的地方插入分号。另一种方式是使用反引号 ` 作为 原始 字符串符号:

//正确的方式二:
s := `Starting part
Ending part`

fmt.Printf("Value is: %v", s)//Printf() 的 %v 参数含义是用默格式打印这个值  

控制结构

在 Go 中只有很少的几个控制结构例如这里没有 do 或者 while 循环,只有
for 。有(灵活的) switch 语句和 if ,而 switch 接受像 for 那样可选的初始化语句。还有叫做类型选择和多路通讯转接器的 select,语法有所不同(同 C 相比):
无需圆括号,而语句体必须 总是 包含在大括号内。

if

if x > 0 { //← { 是强制的
    return y
} else {
    return x
}
//===============
//下面的语法在 Go 中是非法的:
if err ! = nil
{    // ← 必须同 if 在同一行
    return err
}
//if 和 switch 接受初始化语句,通常用于设置一个(局部)变量。
if err := Chmod(0664) ; err ! = nil { //← nil 与 C 的 NULL 类似
    fmt.Printf(err) //← err 的作用域被限定在 if 内
    return err
}

goto

Go 有 goto 语句——明智的使用它。用 goto 跳转到一定是当前函数内定义的标签。例如假设这样一个循环:

package main 

func main() {
    myfunc()

}
func myfunc() {
    i := 0
Here:   // ← 这行的第一个词,以分号结束作为标签,标签大小写敏感
    println(i)
    i++
    if i > 10 { //打印1  到  10 ,这里不加条件会是无限循环
        return 
    }
    goto Here// ← 跳转
}

for循环

Go 的 for 循环有三种形式,只有其中的一种使用分号。

for init ; condition ; post { } //← 和 C 的 for 一样
for condition { } //← 和 while 一样
for { } //← 死循环
//由于 Go 没有逗号表达式,而 ++ 和 – 是语句而不是表达式,如果你想在 for 中
//执行多个变量,应当使用 平行赋值。
// Reverse a
for i, j := 0, len (a)-1 ; i < j ; i, j = i+1, j-1 {
    a[i], a[j] = a[j], a[i] //← 平行赋值
}

break 和 continue
循环嵌套循环时,可以在 break 后指定标签。用标签决定 哪个 循环被终止:

package main 

func main() {
    myfunc()

}
func myfunc() {
    for j := 0 ; j < 5 ; j++ {
        for i := 0 ; i < 10 ; i++ {
            if i > 2 {
                break  //← 现在终止的是 j 循环,而不是 i 的那个
            }
            println(i)
        }
        println(j)
    }
}
//continue
package main 

func main() {

    for i := 0 ; i < 10 ; i++ {
        if i > 5 {
            continue //← 跳过循环中所有的代码 println(i)
        }
        println(i)
    }
}

range迭代器

range 是个迭代器,当被调用的时候,从它循环的内容中返回一个键值对

package main 
import "fmt"
func main() {

    list := [] string { "a", "b", "c", "d", "e", "f" }

    for k, v := range list {

        // 对 k 和 v 做想做的事情
        fmt.Printf("list[%d] = %s\n",k,v)
    }
}
// list[0] = a
// list[1] = b
// list[2] = c
// list[3] = d
// list[4] = e
// list[5] = f

switch

可以使用 fallthrough 使其匹配失败后自动向下尝试。
没有 fallthrough :

switch i {
    case 0: // 空的 case 体
    case 1:
        f() // 当 i == 0 时, f 不会被调用!
}

而这样:

switch i {
    case 0: fallthrough
    case 1:
        f() // 当 i == 0 时, f 会被调用!
}

用 default 可以指定当其他所有分支都不匹配的时候的行为。

switch i {
    case 0:
    case 1:
        f()
    default :
        g() // 当 i 不等于 0 或 1 时调用
}

分支可以使用逗号分隔的列表。

package main 
// import "fmt"
func main() {
    println(shouldEscape('?'))  //true
}

func shouldEscape(c byte ) bool {
    switch c {
        case ' ', '?', '&', '=', '#', '+':// ← , as ”or”
        return true
    }
    return false
}

内建函数

 //Go 中的预定义函数
close new panic complex
delete make recover real
len append print imag
cap copy println

可以使用命令查看函数文档

go doc builtin // 获得关于内建类型和函数的在线文档。

查看某个函数文档

//获得copy的文档  go doc builtin copy

这里写图片描述

close
//用于 channel 通讯。使用它来关闭 channel,
delete
//用于在 map 中删除实例。
lencap
//可用于不同的类型, len 用于返回字符串、slice 和数组的长度。
new
//用于各种类型的内存分配。
make
//用于内建类型(map、slice 和 channel)的内存分配。
copy
//用于复制 slice。
append
//用于追加 slice。
panicrecover
//用于 异常 处理机制。

printprintln
//是底层打印函数,可以在不引入 fmt 包的情况下使用。它们主要用于调试。
complexrealimag
//全部用于处理 复数。

array、slices 和 map

array

array 由 [n]<type> 定义,n 标示 array 的长度,而 <type> 标示希望存储的内容的类型。对 array 的元素赋值或索引是由方括号完成的:

package main 
import "fmt"
func main() {
    // var arr = [10] int 这样的数组类型有固定的大小。大小是类型的一部分 。由于不同的大小是不同的类型,因此不能改变大小
    var arr [10] int
    arr[0] = 42
    arr[1] = 13
    fmt.Printf("The first element is %d\n", arr[0]) 
}

var arr = [10] int 这样的数组类型有固定的大小。大小是类型的一部分 。由于不同的大小是不同的类型,因此不能改变大小。数组同样是值类型的:将一个数组赋值给另一个数组,会 复制 所有的元素。尤其是当向函数内传递一个数组的时候,它会获得一个数组的副本,而不是数组的指针

可以像这样声明一个数组:var a [3] int,如果不使用零来初始化它,则用复合声明:
a := [3] int{ 1, 2, 3 } 也可以简写为 a := [...] int{ 1, 2, 3 },Go 会自动统计元素的个数。

//多维数组
a := [3][2] int { [2] int { 1,2 } , [2] int { 3,4 } , [2] int { 5,6 } }

slice

slice 是一个 指向 array 的指针,这是其与 array 不同的地方;slice 是引用
类型,这意味着当赋值某个 slice 到另外一个变量,两个引用会指向同一个 array。

sl := make ([] int , 10)
//错误的示例,如果要扩展slice需要使用append和copy
package main
func main() {
    var array [100] int //← Create array, index from 0 to 99
    slice := array[0:99] //← Create slice, index from 0 to 98
    slice[98] = 'a'// ← OK
    slice[99] = 'a'// ← Error: ”throw: index out of range”
}

使用append扩展slice

package main
import "fmt"
func main() {

    s0 := [] int { 0, 0 }

    s1 := append (s0, 2)//追加一个元素, s1 == []int{0, 0, 2} ;

    fmt.Printf("%v\n",s1)

    s2 := append (s1, 3, 5, 7)//追加多个元素, s2 == []int{0, 0, 2, 3, 5, 7} ;

    fmt.Printf("%v\n",s2)
    //...可变长参数  http://studygolang.com/articles/1965
    s3 := append (s2, s0...)//追加一个 slice, s3 == []int{0, 0, 2, 3, 5, 7, 0, 0} 。注意这三个点!

    fmt.Printf("%v\n",s3)
}
// [0 0 2]
// [0 0 2 3 5 7]
// [0 0 2 3 5 7 0 0]

copy的使用

package main
import "fmt"
func main() {

    var a = [...] int { 0, 1, 2, 3, 4, 5, 6, 7 }
    var s = make ([] int , 6)
    n1 := copy (s, a[0:])// ← n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
    fmt.Printf("%v\n",s)
    fmt.Printf("%v\n",n1)
    //copy返回拷贝的元素个数
    n2 := copy (s, s[2:])// ← n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
    fmt.Printf("%v\n",s)    
    fmt.Printf("%v\n",n2)
}

map

一般定义 map 的方法是: map[<from type>]<to type>

package main
import "fmt"
func main() {

    monthdays := map [ string ] int {
    "Jan": 31, "Feb": 28, "Mar": 31,
    "Apr": 30, "May": 31, "Jun": 30,
    "Jul": 31, "Aug": 31, "Sep": 30,
    "Oct": 31, "Nov": 30, "Dec": 31,// ← 逗号是必须的
    }
    // monthdays := make ( map[ string ] int )//当只需要声明一个 map 的时候,使用 make 的形式
    fmt.Printf("%d\n", monthdays["Dec"])//打印出 12 月的天数
    year := 0
    for _, days := range monthdays { //← 键没有使用,因此用 _, days
        year += days
    }
    fmt.Printf("Numbers of days in a year: %d\n", year)
    //向 map 增加元素,可以这样做:
    monthdays["Undecim"] = 30 //← 添加一个月
    monthdays["Feb"] = 29 //← 闰年时重写这个元素
    //检查元素是否存在的两种方式
    //var value int
    var present bool
    //value, present = monthdays["Jan"]
    _, present = monthdays["Jan"] //← 如果存在, present 则有值 true
    println(present)
    //← 或者更接近 Go 的方式
    //v, ok := monthdays["Jan"]
    _, ok := monthdays["Jan"]// ← “逗号 ok ”形式    
    println(ok)
    //也可以从 map 中移除元素:
    delete(monthdays, "Mar") //← 删除 ”Mar” 吧
}


参考文章:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值