七叶笔记 » golang编程 » go语言基础笔记

go语言基础笔记

1、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

2、关键字下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

break default func interface selectcase defer go map structchan else goto package switchconst fallthrough if range typecontinue for import return var除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

append bool byte cap close complex complex64 complex128 uint16copy false float32 float64 imag int int8 int16 uint32int32 int64 iota len make new nil panic uint64print println real recover string true uint uint8 uintptr程序一般由关键字、常量、变量、运算符、类型和函数组成。程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。程序中可能会使用到这些标点符号:.、,、;、: 和 …。

3、程序一般结构

 // 当前程序的包名
package main

// 导入其他包
import . "fmt"

// 常量定义
const PI = 3.14

// 全局变量的声明和赋值
var name = "gopher"

// 一般类型声明
type newType int

// 结构的声明
type gopher struct{}

// 接口的声明
type golang interface{}

// 由main函数作为程序入口点启动
func main() {
    Println("Hello World!")
}
  

4、导入只有 package 名称为 main 的包可以包含 main 函数。一个可执行程序有且仅有一个 main 包。

import “fmt”import “io”

或者import {“fmt”,“io”}

别名:package 别名:// 为fmt起别名为fmt2import fmt2 “fmt”

5、通过 const 关键字来进行常量的定义。通过在函数体外部使用 var 关键字来进行全局变量的声明和赋值。通过 type 关键字来进行结构(struct)和接口(interface)的声明。通过 func 关键字来进行函数的声明。可见性规则Go语言中,使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包所调用。函数名首字母小写即为 private

6、数据类型1)布尔型var b bool = true2)数字类型1 uint8 无符号 8 位整型 (0 到 255)2 uint16 无符号 16 位整型 (0 到 65535)3 uint32 无符号 32 位整型 (0 到 4294967295)4 uint64 无符号 64 位整型 (0 到 18446744073709551615)5 int8 有符号 8 位整型 (-128 到 127)6 int16 有符号 16 位整型 (-32768 到 32767)7 int32 有符号 32 位整型 (-2147483648 到 2147483647)8 int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)

浮点型:1 float32 IEEE-754 32位浮点型数2 float64 IEEE-754 64位浮点型数3 complex64 32 位实数和虚数4 complex128 64 位实数和虚数

其他数字类型1 byte 类似 uint82 rune 类似 int323 uint 32 或 64 位4 int 与 uint 一样大小5 uintptr 无符号整型,用于存放一个指针

go 1.9版本对于数字类型,无需定义int及float32、float64,系统会自动识别在 Go 中,布尔值的类型为 bool,值是 true 或 false,默认为 false。

7、变量声明1) 三种声明方式:var a int = 10var b = 10 (自行判定变量类型)c := 102) 多变量声明//类型相同多个变量, 非全局变量var vname1, vname2, vname3 typevname1, vname2, vname3 = v1, v2, v3var vname1, vname2, vname3 = v1, v2, v3 //自行判定变量类型vname1, vname2, vname3 := v1, v2, v3 //这种不带声明格式的只能在函数体中出现

// 这种因式分解关键字的写法一般用于声明全局变量var (vname1 v_type1vname2 v_type2)

变量赋值:_, b = 5, 7 (5被抛弃,_空白标示符)

&i —获取变量i的内存地址局部变量定义后不使用会报错并行赋值可以用于函数 val, err = Func1(var1)

8、常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型显式类型定义: const b string = “abc”隐式类型定义: const b = “abc”枚举常量:const (Unknown = 0Female = 1Male = 2)常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:package mainimport “unsafe”const (a = “abc”b = len(a)c = unsafe.Sizeof(a))

特殊常量:iota在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。iota 可以被用作枚举值:const (a = iotab = iotac = iota)第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:const (a = iotabc)用法示例:package mainimport “fmt”func main() {const (a = iota //0b //1c //2d = “ha” //独立值,iota += 1e //”ha” iota += 1f = 100 //iota +=1g //100 iota +=1h = iota //7,恢复计数i //8)fmt.Println(a,b,c,d,e,f,g,h,i)}结果:0 1 2 ha ha 100 100 7 8

特别示例:

 package main
import "fmt"
const (
    i=1<<iota
    j=3<<iota
    k
    l
)

func main() {
    fmt.Println("i=",i)
    fmt.Println("j=",j)
    fmt.Println("k=",k)
    fmt.Println("l=",l)
}
  

结果:i= 1j= 6k= 12l= 24解释:iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3

9、语言运算符算术运算符: + – * / % ++ —关系运算符:== != > < >= <=逻辑运算符: && || !位运算符: & | ^ << >>赋值运算符:= += -= *= /= %= <<= >>= &= ^= |=其他运算符:&-返回变量存储地址 *-指针变量运算符优先级7 ^ !6 * / % << >> & &^5 + – | ^4 == != < <= >= >3 <-2 &&1 ||

10、语言条件语句if…elseswitch: 语句用于基于不同条件执行不同动作select: select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。11、语言循环语句for break continue goto示例无限循环:

 package main
import "fmt"
func main() {
    for true  {
        fmt.Printf("这是无限循环。\n");
    }
}
  

12、函数func function_name( [parameter list] ) [return_types] {函数体}示例:

 package main
import "fmt"
func swap(x, y string) (string, string) {
   return y, x
}
func main() {
   a, b := swap("Mahesh", "Kumar")
   fmt.Println(a, b)
}
  

函数参数:值传递、引用传递函数作为值:

 package main
import (
   "fmt"
   "math"
)
func main(){
   getSquareRoot := func(x float64) float64 {
      return math.Sqrt(x)
   }
   fmt.Println(getSquareRoot(9))
}
  

闭包:

 package main
import "fmt"
func getSequence() func() int {
    i := 0
    return func() int {
        i += 1
        return i
    }
}
func main() {
    /* nextNumber 为一个函数,函数 i 为 0 */    nextNumber := getSequence()
    /* 调用 nextNumber 函数,i 变量自增 1 并返回 */    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    /* 创建新的函数 nextNumber1,并查看结果 */    nextNumber1 := getSequence()
    fmt.Println(nextNumber1())
    fmt.Println(nextNumber1())
}

  

方法一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针,语法格式:func (variable_name variable_data_type) function_name() [return_type]{/* 函数体*/}

示例:

 package main
import (
   "fmt"  
)
/* 定义结构体 */type Circle struct {
  radius float64
}
func main() {
  var c1 Circle
  c1.radius = 10.00
  fmt.Println("Area of Circle(c1) = ", c1.getArea())
}
  

//该 method 属于 Circle 类型对象中的方法func (c Circle) getArea() float64 {//c.radius 即为 Circle 类型对象中的属性return 3.14 * c.radius * c.radius}

13、数组var variable_name [SIZE] variable_type;1)初始化var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} //初始化数组中 {} 中的元素个数不能大于 [] 中的数字。如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:var balance = […]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

2) 向函数传递数组void myFunction(param [10]int) {}void myFunction(param []int) {}

14、指针var var_name *var-type空指针判断:if(ptr != nil)

15、结构体定义:type struct_variable_type struct {member definition;member definition;…member definition;}使用,声明:variable_name := structure_variable_type {value1, value2…valuen}结构体使用: 结构体.成员名结构体的指针,不像想像的结果:

 package main
import "fmt"
type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* Declare Book1 of type Book */   var Book2 Books        /* Declare Book2 of type Book */
   /* book 1 描述 */   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700
   /* 打印 Book1 信息 */   printBook(&Book1)
   /* 打印 Book2 信息 */   printBook(&Book2)
}
func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}
  

结果:Book title : Go 语言Book author : www.runoob.comBook subject : Go 语言教程Book book_id : 6495407Book title : Python 教程Book author : www.runoob.comBook subject : Python 语言教程Book book_id : 6495700

16、语言切片–动态数组定义:未指定大小切片: var identifier []type指定长度:var slice1 []type = make([]type, len) 简写:slice1 := make([]type, len)这里 len 是数组的长度并且也是切片的初始长度。初始化:s :=[] int {1,2,3 }s := arr[startIndex:endIndex] //初始化切片s,是数组arr的引用s :=make([]int,len,cap) //通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片切片是可索引的,并且可以由 len() 方法获取长度cap(): 计算切片容量,最长可以达到多少一个切片在未初始化之前默认为 nil,长度为 0

append() 和 copy() 函数:package mainimport “fmt”func main() {var numbers []intprintSlice(numbers)/* 允许追加空切片 /
numbers = append(numbers, 0)
printSlice(numbers)
/ 向切片添加一个元素 /
numbers = append(numbers, 1)
printSlice(numbers)
/ 同时添加多个元素 /
numbers = append(numbers, 2, 3, 4)
printSlice(numbers)
/ 创建切片 numbers1 是之前切片的两倍容量/
numbers1 := make([]int, len(numbers), (cap(numbers))2)/* 拷贝 numbers 的内容到 numbers1 */copy(numbers1, numbers)printSlice(numbers1)}func printSlice(x []int) {fmt.Printf(“len=%d cap=%d slice=%v\n”, len(x), cap(x), x)}

17、范围(Range)示例:package mainimport “fmt”func main() {//这是我们使用range去求一个slice的和。使用数组跟这个很类似nums := []int{2, 3, 4}sum := 0for _, num := range nums {sum += num}fmt.Println(“sum:”, sum)//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符”_”省略了。有时侯我们确实需要知道它的索引。for i, num := range nums {if num == 3 {fmt.Println(“index:”, i)}}//range也可以用在map的键值对上。kvs := map[string]string{“a”: “apple”, “b”: “banana”}for k, v := range kvs {fmt.Printf(“%s -> %s\n”, k, v)}//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。for i, c := range “go” {fmt.Println(i, c)}}结果:sum: 9index: 1b -> bananaa -> apple0 1031 111

18、Map(集合)定义:/* 声明变量,默认 map 是 nil */var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */map_variable := make(map[key_data_type]value_data_type)示例:

 package main
import "fmt"
func main() {
    var countryCapitalMap map[string]string /*创建集合 */    countryCapitalMap = make(map[string]string)

    /* map插入key - value对,各个国家对应的首都 */    countryCapitalMap["France"] = "Paris"
    countryCapitalMap["Italy"] = "罗马"
    countryCapitalMap["Japan"] = "东京"
    countryCapitalMap["India"] = "新德里"

    /*使用键输出地图值*/    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap[country])
    }

    /*查看元素在集合中是否存在 */    captial, ok := countryCapitalMap["India"] /*如果确定是真实的,则存在,否则不存在 */    fmt.Println(captial)
    fmt.Println(ok)
    if ok {
        fmt.Println("美国的首都是", captial)
    } else {
        fmt.Println("美国的首都不存在")
    }
}
  

删除:delete(countryCapitalMap, “France”)

19、递归函数20、类型转换type_name(expression)21、接口/* 定义接口 */type interface_name interface {method_name1 [return_type]method_name2 [return_type]method_name3 [return_type]…method_namen [return_type]}

/* 定义结构体 /
type struct_name struct {
/ variables */}

/* 实现接口方法 /
func (struct_name_variable struct_name) method_name1() [return_type] {
/ 方法实现 /
}

func (struct_name_variable struct_name) method_namen() [return_type] {
/ 方法实现*/}

 package main
import (
    "fmt"
)
type Phone interface {
    call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
    fmt.Println("I am iPhone, I can call you!")
}
func main() {
    var phone Phone
    phone = new(NokiaPhone)
    phone.call()
    phone = new(IPhone)
    phone.call()
}
  

22、错误处理type error interface {Error() string}

 package main
import (
    "fmt"
)
// 定义一个 DivideError 结构
type DivideError struct {
    dividee int
    divider int
}
// 实现 `error` 接口
func (de *DivideError) Error() string {
    strFormat := `
    Cannot proceed, the divider is zero.
    dividee: %d
    divider: 0`
    return fmt.Sprintf(strFormat, de.dividee)
}
// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
    if varDivider == 0 {
        dData := DivideError{
            dividee: varDividee,
            divider: varDivider,
        }
        errorMsg = dData.Error()
        return
    } else {
        return varDividee / varDivider, ""
    }
}
func main() {
    // 正常情况
    if result, errorMsg := Divide(100, 10); errorMsg == "" {
        fmt.Println("100/10 = ", result)
    }
    // 当被除数为零的时候会返回错误信息
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
        fmt.Println("errorMsg is: ", errorMsg)
    }
}  

相关文章