Go语言入门指南——基础语法

Hello,world!

开始学习Go语言前,我们先从一段简单的代码引入:

package main
import "fmt" 
func main() { 
fmt.Println("Hello,world!")
 }

Go语言的代码通过包(package)组织,包类似于其它语言里的库(libraries)或者模块(modules)。一个包由位于单个目录下的一个或多个.go源代码文件组成, 目录定义包的作用。import声明必须跟在文件的package声明之后。

随后,则是组成程序的函数、变量、常量、类型的声明语句(分别由关键字 func, var, const, type 定义)。我们需要注意的是:必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过。

Go语言在代码格式上采取了很强硬的态度。Go语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。函数的左括号 { 必须和func函数声明在同一行上, 且位于末尾,不能独占一行。

基础数据类型

  • 整型:int8 int16 int32 int64(有符号)uint8 uint16 uint32 uint64(无符号)
  • 浮点型:float32 float64
  • 复数:complex64 complex128(与浮点型对应)
  • 布尔型:true false
  • 字符串型:采用UTF8编码的Unicode码点(rune)序列
  • 常量:const 常量的值不可修改,所有常量的运算都可以在编译期完成
  • 变量:var 变量名字 类型 = 表达式(var声明语句)

复合数据类型

  • 数组:一个由固定长度的特定类型元素组成的序列,数组的每个元素可以通过索引下标来访问
  • 函数:函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体                
    func function_name(parameter_list) (result_types){}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,参数列表和返回值类型构成了函数签名。
  • parameter_list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

函数的递归:

函数可以直接或间接的调用自身,可以解决计算阶乘,生成斐波那契数列等数学问题

以下程序采用函数递归计算数的阶乘:

package main  
import "fmt"  
  
func Factorial(n uint64)(result uint64) {  
    if (n > 0) {  
        result = n * Factorial(n-1)  
        return result  
    }  
    return 1  
}  
  
func main() {    
    var i int = 15  
    fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))  
}
  • Slice(切片):是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能

image.png

Q2 := months[4:7]
summer := months[6:9]
fmt.Println(Q2)     // ["April" "May" "June"]
fmt.Println(summer) // ["June" "July" "August"]
  • Map(哈希表):一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value
    内置的make函数可以创建一个map: make(map[string]int)

我们也可以用map字面值的语法创建map,同时还可以指定一些最初的 key/value:

ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}
  • struct(结构体):一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员
type Employee struct {
    ID        int
    Name      string
    Address   string
    DoB       time.Time
    Position  string
    Salary    int
    ManagerID int
}

var dilbert Employee
  • Range(范围):用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对
    代码中的 key 和 value 是可以省略的: for _, value := range oldMap

  • Pointer(指针):一个指针变量指向了一个值的内存地址,当一个指针被定义后没有分配到任何变量时,它的值为 nil: var ip *int /* 指向整型*/

  • interface(接口):通过将接口作为参数来实现对不同类型的调用实现多态

/* 定义接口 */
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] {
   /* 方法实现*/
}
  • channel(通道):是一个通信机制,它可以让一个goroutine(并发执行单元)通过它给另一个goroutine发送值信息,使用内置的make函数,我们可以创建一个channel: make(chan 元素类型, [缓冲大小])

通道分类:

  1. 无缓冲通道 make(chan int)
  2. 有缓冲通道 make(chan int, 2)

注释

单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾。 // 单行注释 /* 多行注释 */

转换字符

转换字符含义
%d十进制整数
%x, %o, %b十六进制,八进制,二进制整数
%f, %g, %e浮点数: 3.141593 3.141592653589793 3.141593e+00
%t布尔:true或false
%c字符(rune) (Unicode码点)
%s字符串
%q带双引号的字符串"abc"或带单引号的字符'c'
%v变量的自然形式(natural format)
%T变量的类型
%%字面上的百分号标志(无操作数)

并发

在Go语言中,每一个并发的执行单元叫作一个goroutine,goroutine 是轻量级线程,当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine,新的goroutine会用go语句来创建。

package main

import (
        "fmt"
        "time"
)

func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}

func main() {
        go say("world")
        say("hello")
}

封装

封装提供了三方面的优点。首先,因为调用方不能直接修改对象的变量值,其只需要关注少量的语句并且只要弄懂少量变量的可能的值即可。

第二,隐藏实现的细节可以防止调用方依赖那些可能变化的具体实现,这样使设计包的程序员在不破坏对外的api情况下能得到更大的自由。

封装的第三个优点也是最重要的优点,是阻止了外部调用方对对象内部的值任意地进行修改。因为对象内部变量只可以被同一个包内的函数修改,所以包的作者可以让这些函数确保对象内部的一些值的不变性。

比如log包里的Logger类型对应的一些函数。在命名一个getter方法时,我们通常会省略掉前面的Get前缀。这种简洁上的偏好也可以推广到各种类型的前缀比如Fetch,Find或者Lookup。

package log
type Logger struct {
    flags  int
    prefix string
    // ...
}
func (l *Logger) Flags() int
func (l *Logger) SetFlags(flag int)
func (l *Logger) Prefix() string
func (l *Logger) SetPrefix(prefix string)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值