Golang最最最基础语法

Azen · · 3453 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

这一节看下Golang的基础语法...嘛...如果懒得看的话,记得以下两点就好:
1 Golang的变量、函数参数等等涉及到类型的声明,都是变量名写在前,类型写在后的(和正统C系语法刚好相反)
2 循环语句for通吃所有
然后,就开始啦~

Go语言基本语法

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello Azen٩(●˙▿˙●)۶…⋆ฺ")
}

作用:使用fmt这个库运行输出

定义变量

var 关键字

func variableZeroValueDefine() {
    var a int
    var s string
    fmt.Printf("%d %q\n", a, s)
}

知识点:

  1. 变量名写在前面,变量类型写在后面
    原因:在定义变量的时候,往往是先想到名字,再想到变量类型
  2. 定义完变量后,变量都是有默认初值的。
    2.1. int类型的初值为0
    2.2. string类型的初始为空串 - 使用%q可打印空串,展示结果为→ ""

同时定义变量并赋初值

注意:变量定义后,一定要用到,否则编译器报错。

func varibaleInitial() {
    var a, b int = 1, 2
    var s string = "猜猜我是谁"
    fmt.Println(a, b, s)
}

此例中,int 和 string是多余的,编译器可以做类型推断 - Type Deduction

类型推断

func varibaleTypeDeduction() {
    var a, b, c, s = 1, 2, true, "ㄟ..."
    b = 666
    fmt.Println(a, b, c, s)
}

:=定义并赋初值

更推荐用这种方式定义并初始化变量

func varibaleShortcut() {
    a, b := 233, 666
    s := "老铁蛤蛤蛤"
    fmt.Println(a, b, s)
}

在函数外定义变量

var a, b int
var ss = "总想搞个大新闻"

在函数外面定义的变量,不是全局变量,而是包内变量
Go语言木有全局变量的说法。

注意:在函数外定义变量不能用:=的方式,一定要被var关键字修饰

使用()定义多个包内变量

可以把变量定义在括号中,以减少var关键字的使用数量

var (
    s string
    a, b int
    // a, b := 666, 233 // 全局变量不能用:=定义
)
var ss = "总想搞个大新闻"

内建变量类型

  • bool,string
  • (u)int, (u)int8, (u)int16, (u)int32, (u)int64, uintptr
    • 没跟长度,则长度按操作系统位数而定
    • uintptr是个指针
  • 字符型
    • byte
    • rune
      • 不是char,char只有1个字节
      • rune的长度为32位,4字节,为应对全球化的字符
  • 浮点数
    • float32,float64
    • complex64,complex128
      • 复数,有实部和虚部
      • complex64的实部和虚部为32位
      • complex128的实部和虚部为64位
      • 把复数直接作为内建变量的类型

强制类型转换

Golang只有强制类型转换,没有隐式类型转换
示例:计算斜边的长度
a = 3 b = 4 求斜边c

func triangle() {
    var a, b = 3, 4
    var c int
    c = int(math.Sqrt(float64(a * a + b * b)))
    fmt.Println(c)
}

math.Sqrt函数的入参和出参都是float64,所以需要强制转换。

常量的定义

关键字:const
常量类型可规定也可不规定

  • 如果不规定类型,常量会像「文本替换」功能一样(类似宏定义),到使用它的地方再决定类型

Golang中不会把常量全部大写,因为首字母大写在golang中代表作用域为public

func consts() {
    const (
        filename = "abc.txt"
        a, b     = 3, 4
    )
    var c int
    c = int(math.Sqrt(a * a + b * b))
    fmt.Println(filename, c)
}

*注:上面的a*a就不用强制转为float64,因为被当成类似「宏替换」了

枚举类型

基本定义:就定义成一组const就好

func enums() {
    const (
        azen  = 0
        daker = 1
        buran = 2
    )
    fmt.Println(azen, daker, buran)
}

iota自增值

定义枚举

func enums() {
    const (
        azen  = iota
        daker
        _
        buran
    )
    fmt.Println(azen, daker, buran)
}

iota参与运算

const (
    b = 1 << (10 * iota)
    kb
    mb
    gb
    tb
    pb
)

条件语句

if语句

func bounded(v int) int {
    if v > 100 {
        return 100
    } else if v < 0 {
        return 0
    } else {
        return v
    }
}

特点:if条件不需要用括号包裹
示例:

func ReadFile(filename string) ([]byte, error)

返回两个值:

  • [ ]byte 是读取到的文件内容数组 - 使用%s打印内容
  • error 是出错信息
func fileRead() {
    const filename = "abc.txt"
    contents, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Println(contents)
    } else {
        fmt.Println(err)
    }
}

使用;简化条件

func fileRead() {
    const filename = "abc.txt"
    if contents, err := ioutil.ReadFile(filename); err != nil {
        fmt.Println(contents)
    } else {
        fmt.Println(err)
    }
}

在条件中可以用:=做声明和赋值
出了if的作用域就不能访问如上定义的content和err了

switch语句

基本用法

func eval(a, b int, op string) int {
    var result int
    switch op {
    case "+":
        result = a + b
    case "-":
        result = a - b
    case "*":
        result = a * b
    case "/":
        result = a / b
    default:
        panic("不支持的操作类型")
    }
    return result
}

特点:

  • 不需要加break,默认都有break.
  • 如果不需要break,手动加fallthrough - 这一点和swift一样

panic

抛出一个错误 - 类似于NSError的raise

switch后不接表达式

在case中加入条件即可

func grade(score int) string {
    var g string
    switch {
    case score < 0 || score > 100:
        panic(fmt.Sprintf("Wrong score: %d", score))
    case score < 60:
        g = "F"
    case score < 80:
        g = "B"
    case score < 90:
        g = "A"
    case score <= 100:
        g = "SSR"
    }
    return g
}

循环语句

for语句

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

栗子:转二进制

转二进制的思路:不断取模,获得的数字往前加

func convertToBin(number int) string {
    result := ""
    for ; number > 0; number /= 2 {
        lsb := number % 2
        result = strconv.Itoa(lsb) + result
    }
    return result
}

strconv.Itoa → 将int转为string

for的while用法(只有结束条件)

func pintFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
 
    scanner := bufio.NewScanner(file)

    //  func (s *Scanner) Scan() bool - 在读完或报错的时候,会返回false
    for scanner.Scan() {
         
    }
}

当for 语句中,省略其实条件、递增条件,只有结束条件的时候,类似于while

for省略所有表达式 - 死循环

func forever() {
    for {
        fmt.Println("Bilibili")
    }
}

Golang中经常要用到死循环,goroutine的肚子里就是死循环。好多死循环的goroutine在互相进行通讯。 - 这和iOS开发中的runloop是一样一样的

函数定义

func eval(a, b int, op string) int

函数名在前,类型在后。和变量定义思路一致

基本示例

func convertToBin(number int) string {
    result := ""
    for ; number > 0; number /= 2 {
        lsb := number % 2
        result = strconv.Itoa(lsb) + result
    }
    return result
}

函数返回多个值示例

带余除法

func div(a, b int) (int, int) {
    return a / b, a % b
}

给返回值起名字

好处是可读性更强,函数调用者可以很方便的知道返回值是啥...

func div(a, b int) (q, r int) {
    return a / b, a % b
}

如下写法也可以正确返回q和r,但是可读性不强,不建议这样写

func divNoRecommend(a, b int) (q, r int) {
    q = a / b
    r = a % b
    return
}

多返回值只使用一个

result, _ := div(10, 7)

多值返回的习惯用法

第一个值返回正常值,第二个值返回error

函数和函数式编程

函数在Golang中是一等公民,函数可以作为参数、返回值

函数作为参数

func apply(op func(a, b int) int, a, b int) (result int)  {
    return op(a, b)
}

打印下op看看它是谁

  • 拿函数名
    • 需要用reflect.ValueOf(op).Pointer()拿到这个函数的指针
    • 使用runtime获取函数名runtime.FuncForPC(p).Name()
func apply(op func(a, b int) int, a, b int) (result int)  {
    p := reflect.ValueOf(op).Pointer()
    opName := runtime.FuncForPC(p).Name()
    fmt.Println(opName)
    return op(a, b)
}

匿名函数作为函数参数

fmt.Println(
    apply(func (a, b int) int {
        return a + b
    }, 10, 20),
)

Golang没有花哨的lambda表达式

函数其他说明

可变参数列表

可变参数列表的使用方法,可以和数组一样用

func sum(numbers ...int) int {
    result := 0
    for i := range numbers {
        result += numbers[i]
    }
    return result
}

没有默认参数、可选参数概念

指针

func pointerDefine() {
    var a = 0
    var pa *int = &a
    *pa = 0x66CCFF
    fmt.Println(a)
}

特点

  • 指针不能运算
    • C可以拿到指针的头指针做加法运算 - 步长由指针类型决定

函数参数传递

C、C++、OC可以值传,也可以引用传
Java和Python基本上都是引用传递

Golang只有值传递一种方式

凡调函数,参数都会拷贝一份 - 和指针配合,实现相当引用传递的效果

举例:交换两个变量的值

func swap(a, b *int) {
    *a, *b = *b, *a
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:Azen

查看原文:Golang最最最基础语法

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3453 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传