Python 程序员的 Golang 学习指南(III): 入门篇

基础语法

类型和关键字

  • 类型
// 基础类型
布尔类型: bool
整型: int8,uint8,int16,uint16,int32,uint32,int64,uint64,int,rune,byte,complex128, complex64,其中,byte 是 int8 的别名
浮点类型: float32 、 float64
复数类型: complex64 、 complex128
字符串: string
字符类型: rune(int32的别名)
错误类型: error

// 复合类型
指针(pointer)
数组(array)
切片(slice)
字典(map)
通道(chan)
结构体(struct)
接口(interface)
  • 关键字
break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

变量

Go 同其他语言不同的地方在于变量的类型在变量名的后面,不是 int a,而是 a int。至于为什么这么定义,Go 的官方博客有给出解释,有兴趣的可以参考下。

变量定义语法如下:

var a int
a = 2

// 或者
a := 2

// 同时定义多个变量
var (
    a int
    b bool
)

// 同时给多个变量赋值
a, b := 2, true

操作符

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
     &^          &^=

控制结构

Go 语言支持如下的几种流程控制语句:

  • 条件语句,对应的关键字为 if、else 和 else if;
  • 选择语句,对应的关键字为 switch、case 和 select;
  • 循环语句,对应的关键字为 for 和 range;
  • 跳转语句,对应的关键字为 goto。

值得一提的是,Go 语言并不支持 do 或者 while 关键字,而是对 for 关键字做了增强,以实现类似的效果,如下:

for {
    // 实现无限循环,慎用!
}

常用内置函数

  • len:计算(字符串,数组或者切片,map)长度
  • cap:计算(数组或者切片,map)容量
  • close:关闭通道
  • append:追加内容到切片
  • copy:拷贝数组/切片内容到另一个数组/切片
  • delete:用于删除 map 的元素

array, slice 和 map

// array
a := [3]int{ 1, 2, 3 } // 等价于 a := [...]int{ 1, 2, 3 }

// slice
s := make([]int , 3) // 创建一个长度为 3 的 slice
s := append(s, 1) // 向 slice 追加元素
s := append(s, 2)

// map
m := make(map[string]int) // 使用前必须先初始化
m["golang"] = 7

关于 array, slice 和 map 的更多惯用法,有一篇文章介绍的挺详细,有兴趣的可以看看。

函数

Go 语言的函数有如下特性:

  • 不定参数

由于 Go 语言不支持函数重载(具体原因见 Go Language FAQ),但我们可以通过不定参数实现类似的效果。

func myfunc(args ...int) {
    // TODO
}

// 可通过如下方式调用
myfunc(2)
myfunc(1, 3, 5)
  • 多返回值

与 C、C++ 和 Java 等开发语言的一个极大不同在于,Go 语言的函数或者成员的方法可以有多 个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码。

func (file *File) Read(b []byte) (n int, err error)

// 我们可以通过下划线(_)来忽略某个返回值
n, _ := f.Read(buf)
  • 匿名函数

匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯 到 1958 年的 Lisp 语言。但是由于各种原因,C 和 C++ 一直都没有对匿名函数给以支持,其他的各 种语言,比如 JavaScript、C# 和 Objective-C 等语言都提供了匿名函数特性,当然也包含Go语言。

匿名函数由一个不带函数名的函数声明和函数体组成,如下:

func(a, b int) bool {
    return a < b
}

匿名函数可以直接赋值给一个变量或者直接执行:

f := func(a, b int) bool {
    return a < b
}

func(a, b int) bool {
    return a < b
}(3, 4) // 花括号后直接跟参数列表表示函数调用
  • 闭包

闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者 任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含 在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环 境(作用域)。

Go 的匿名函数就是一个闭包。我们来看一个例子:

package main

import "fmt"

func main() {
    j := 5
    a := func() func() {
        i := 10
        return func() {
            fmt.Printf("i, j: %d, %d\n", i, j)
        }
    }()
    a()
    j *= 2
    a()
}

程序输出如下:

i, j: 10, 5
i, j: 10, 10

错误处理

Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try...catch...finally 这种异常,因为 Go 语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在 Go 语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了),才使用 Go 中引入的Exception处理:defer, panic, recover。

用法如下:

package main

import "fmt"

func main() {
    defer func() {
        fmt.Println("recovered:", recover())
    }()
    panic("not good")
}

关于 Go 语言的错误处理机制和传统的 try...catch...finally 异常机制孰优孰劣,属于仁者见仁,智者见智,这里不做赘速。有兴趣的同学可以去看看知乎上的讨论:Go 语言的错误处理机制是一个优秀的设计吗?

面向对象 -> 一切皆类型

Python 推崇“一切皆对象”,而在 Go 语言中,类型才是一等公民。

我们可以这样定义一个结构体:

type Name struct {
    First  string
    Middle string
    Last   string
}

同样也可以定义基础类型:

type SimpleName string

还能给任意类型定义方法:

func (s SimpleName) String() string { return string(s) }
// 或者
func (s string) NoWay()

Golang VS Python

最后我们通过几个例子来比较一下 Golang 与 Python 的一些基本用法,如下:

生成器(Generator)

  • Python 版本
def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
        yield a

for x in fib(10):
    print x

print ‘done‘
  • Golang 版本
package main

import "fmt"

func fib(n int) chan int {
    c := make(chan int)
    go func() {
        a, b := 0, 1
        for i := 0; i < n; i++ {
            a, b = b, a+b
            c <- a
        }
        close(c)
    }()
    return c
}

func main() {
    for x := range fib(10) {
        fmt.Println(x)
    }
}

装饰器(Decorator)

  • Python 版本
from urlparse import urlparse, parse_qs
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

def auth_required(myfunc):
    def checkuser(self):
        user = parse_qs(urlparse(self.path).query).get(‘user‘)
        if user:
            self.user = user[0]
            myfunc(self)
        else:
            self.wfile.write(‘unknown user‘)
    return checkuser

class myHandler(BaseHTTPRequestHandler):
    @auth_required
    def do_GET(self):
        self.wfile.write(‘Hello, %s!‘ % self.user)

if __name__ == ‘__main__‘:
    try:
        server = HTTPServer((‘localhost‘, 8080), myHandler)
        server.serve_forever()
    except KeyboardInterrupt:
        server.socket.close()
  • Golang 版本
package main

import (
    "fmt"
    "net/http"
)

var hiHandler = authRequired(
    func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))
    },
)

func authRequired(f http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if r.FormValue("user") == "" {
            http.Error(w, "unknown user", http.StatusForbidden)
            return
        }
        f(w, r)
    }
}

func main() {
    http.HandleFunc("/hi", hiHandler)
    http.ListenAndServe(":8080", nil)
}

猴子补丁(Monkey patching)

  • Python 版本
import urllib

def say_hi(usr):
    if auth(usr):
        print ‘Hi, %s‘ % usr
    else:
        print ‘unknown user %s‘ % usr

def auth(usr):
    try:
        auth_url = ‘localhost‘
        r = urllib.urlopen(auth_url + ‘/‘ + usr)
        return r.getcode() == 200
    except:
        return False

def sayhitest():
    # Test authenticated user
    globals()[‘auth‘] = lambda x: True
    say_hi(‘John‘)

    # Test unauthenticated user
    globals()[‘auth‘] = lambda x: False
    say_hi(‘John‘)

if __name__ == ‘__main__‘:
    sayhitest()
  • Golang 版本
package main

import (
    "fmt"
    "net/http"
)

func sayHi(user string) {
    if !auth(user) {
        fmt.Printf("unknown user %v\n", user)
        return
    }
    fmt.Printf("Hi, %v\n", user)
}

var auth = func(user string) bool {
    authURL := "localhost"
    res, err := http.Get(authURL + "/" + user)
    return err == nil && res.StatusCode == http.StatusOK
}

func testSayHi() {
    auth = func(string) bool { return true }
    sayHi("John")

    auth = func(string) bool { return false }
    sayHi("John")
}

func main() {
    testSayHi()
}

相关链接:

https://blog.golang.org/gos-declaration-syntax

Go 语言中的 Array,Slice,Map 和 Set

https://golang.org/doc/faq#overloading

Go 语言的错误处理机制是一个优秀的设计吗? - 异常处理

https://talks.golang.org/2013/go4python.slide

Golang 系列教程

Python 程序员的 Golang 学习指南(II): 开发环境搭建

Python 程序员的 Golang 学习指南(I): Go 之初体验

欢迎交流,可以通过我的 Blog 找到我:startover‘s blog

时间: 2024-10-22 22:07:40

Python 程序员的 Golang 学习指南(III): 入门篇的相关文章

Java工程师学习指南(入门篇)

Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都是站在Java后端的全局上进行思考和总结的,忽略了很多小白们的感受,而很多朋友都需要更加基础,更加详细的学习路线. 所以,今天我们重新开一个新的专题,分别按照四篇文章讲述Java的学习路线(分别是入门篇,初级篇,中级篇,高级篇),笔者也打算趁此机会,回忆一下自己的Java学习历程.今天我们要讲的是,

Java程序员的Golang入门指南(上)

Java程序员的Golang入门指南 1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如果有人说X语言比Y语言好,两方的支持者经常会激烈地争吵.如果你是某种语言老手,你就是那门语言的"传道者",下意识地会保护它.无论承认与否,你都已被困在一个隧道里,你看到的完全是局限的.<肖申克的救赎>对此有很好的注脚: [Red] These walls are funny.

Java程序员的Golang入门指南(下)

Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合切片等特性相比Java的确提高了开发效率,但这些在其他语言中也都有,并不是Golang能真正吸引人的地方.不仅是Golang,我们学习任何语言当然都是从基本语法特性着手,但学习时要不断地问自己:使这门语言区别于其他语言的"独到之处"在哪?这种独到之处往往反映了语言的设计思想.出发点.要解决

月薪3万的python程序员都看了这本书

想必大家都看过吧 Python编程从入门到实践 全书共有20章,书中的简介如下: 本书旨在让你尽快学会 Python ,以便能够编写能正确运行的程序 —— 游戏.数据可视化和 Web 应用程序,同时掌握让你终身受益的基本编程知识.本书适合任何年龄的读者阅读,它不要求你有任何 Python 编程经验,甚至不要求你有编程经验.如果你想快速掌握基本的编程知识以便专注于开发感兴趣的项目,并想通过解决有意义的问题来检查你对新学概念的理解程度,那么本书就是为你编写的.本书还可供初中和高中教师用来通过开发项目

程序员带你十天快速入门Python,玩转电脑软件开发(二)

关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到熟悉的效果. 声明:本次教程主要适用于已经习得一门编程语言的程序员.想要学习第二门语言.有梦想,立志做全栈攻城狮的你 如果是小白,也可以学习本教程.不过可能有些困难.如有问题在文章下方进行讨论.或者添加QQ群538742639.群马上就满了,名额不多. 上节课主要讲解了以下内容: 为什么学习Pyth

程序员带你十天快速入门Python,玩转电脑软件开发(三)

声明:本次教程主要适用于已经习得一门编程语言的程序员.想要学习第二门语言.有梦想,立志做全栈攻城狮的你 . 如果是小白,也可以学习本教程.不过可能有些困难.如有问题在文章下方进行讨论.或者添加QQ群538742639.群马上就满了,名额不多. 这是高级程序员快速入门Python语言课程.助你快速学习Python语言.这是第三课. 程序员带你十天快速入门Python,玩转电脑软件开发(一) 程序员带你十天快速入门Python,玩转电脑软件开发(二) 因技术知识连贯性,还没有学习前两课的同学,建议点

CSDN日报20170319——《人工智能风口, Python 程序员的狂欢与企业主的哀嚎》

[程序人生]人工智能风口, Python 程序员的狂欢与企业主的哀嚎 作者:赖勇浩 人工智能风口有多火?估计很多人已经感受到了,我在这里引用一下新智元的报道: "2017年短短不到三个月的时间,国内AI获投项目已有36个,千万级别融资占据半数以上." 嗯,就是那么霸道.两会刚刚结束,"人工智能"首次被列入政府工作报告,随之而来的是人工智能板块领跑大盘涨势,无疑,这一切将刺激人工智能在多个领域的全面发展. [深度学习]NeuralFinder :集成人工生命和遗传算法

程序员带你十天快速入门Python,玩转电脑软件开发(一)

关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到熟悉的效果. 声明:本次教程主要适用于已经习得一门编程语言的程序员.想要学习第二门语言的你.有梦想的你,立志做全栈攻城狮. 如果是小白,也可以学习本教程.不过可能有些困难.如有问题在文章下方进行讨论.或者添加QQ群538742639.群马上就满了,名额不多. 目录: 为什么学习Python? Pyt

Python程序员的10个常见错误(转)

add by zhj:虽然学Python也有两年了,但这些问题的确容易犯,看来对Python的理解还有些地方不深入.先转了,有时间再好好看 译文:http://blog.jobbole.com/68256/ 本文由 伯乐在线 - datorhjaelten 翻译.未经许可,禁止转载!英文出处:toptal.欢迎加入翻译小组. 关于Python Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言.它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Ra