1. 概念汇总

go没有类,但是在type上定义method,这样效果和类用起来很相似

如果说类是对数据和方法的抽象和封装,那么接口就是对类的抽象。

Golang 中没有 class 的概念,而是通过 interface 类型转换支持在动态类型语言中常见的鸭子类型从而达到运行时多态的效果。

关于面向对象、泛型、鸭子类型等概念详见面向对象

网上搜到的interface资料


比较python和go的面向对象写法


不包含父类(或者叫基类)

python

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Person:
    def __init__(self, name):
        self.name = name

    def printName(self):
        print self.name

me = Person('cyent')
me.printName()

go

package main

import "fmt"

type Person struct {
    name string
}

func (p *Person) printName() {
    fmt.Println(p.name)
}

func main() {
    me := Person{name: "cyent"}
    me.printName()
}

输出都是

cyent

继承

使用struct嵌套模拟继承

该例子很经典,包含了父类(或者叫基类)、子类、继承、重写

python

# -*- coding: utf-8 -*-

class SchoolMember:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def tell(self):
        print 'name:"{}", age:"{}"'.format(self.name,self.age)

class Teacher(SchoolMember):
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary

    def tell(self):
        SchoolMember.tell(self)
        print 'Salary: "%d"' % self.salary

class Student(SchoolMember):
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks

    def tell(self):
        SchoolMember.tell(self)
        print 'Marks: "%d"' % self.marks

t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)

t.tell()
s.tell()

输出

name:"Mrs. Shrividya", age:"40"
Salary: "30000"
name:"Swaroop", age:"22"
Marks: "75"

go

package main

import "fmt"

type SchoolMember struct {
    name string
    age int
}

func (this SchoolMember) tell() {
    fmt.Printf("name:\"%s\", age:\"%d\"\n", this.name, this.age)
}

type Teacher struct {
    SchoolMember
    salary int
}

func (this Teacher) tell() {
    this.SchoolMember.tell()
    fmt.Printf("Salary: \"%d\"\n", this.salary)
}

type Student struct {
    SchoolMember
    marks int
}

func (this Student) tell() {
    this.SchoolMember.tell()
    fmt.Printf("Marks: \"%d\"\n", this.marks)
}

func main() {
    t := Teacher{}
    s := Student{}
    t.name = "Mrs. Shrividya"
    t.age = 40
    t.salary = 30000
    s.name = "Swaroop"
    s.age = 22
    s.marks = 75

    t.tell()
    s.tell()
}

Note

上面t := Teacher{}可以用t := new(Teacher)替代,但这2者是有一点区别的,区别在于前者是指针,详见new

输出也是

name:"Mrs. Shrividya", age:"40"
Salary: "30000"
name:"Swaroop", age:"22"
Marks: "75"

更多关于struct嵌套的知识,详见struct作为struct的元素

tar-gz

python

import tarfile
import os

def tar(fname):
    t = tarfile.open(fname + ".tar.gz", "w:gz")
    for root, dir, files in os.walk(fname):
        print root, dir, files
        for file in files:
            fullpath = os.path.join(root, file)
            t.add(fullpath)
    t.close()

if __name__ == "__main__":
    tar("del")

go

package main

import (
    "fmt"
    "os"
    "io"
    "archive/tar"
    "compress/gzip"
)

func main() {
    // file write
    fw, err := os.Create("tar/lin_golang_src.tar.gz")
    if err != nil {
        panic(err)
    }
    defer fw.Close()

    // gzip write
    gw := gzip.NewWriter(fw)
    defer gw.Close()

    // tar write
    tw := tar.NewWriter(gw)
    defer tw.Close()

    // 打开文件夹
    dir, err := os.Open("file/")
    if err != nil {
        panic(nil)
    }
    defer dir.Close()

    // 读取文件列表
    fis, err := dir.Readdir(0)
    if err != nil {
        panic(err)
    }

    // 遍历文件列表
    for _, fi := range fis {
        // 逃过文件夹, 我这里就不递归了
        if fi.IsDir() {
            continue
        }

        // 打印文件名称
        fmt.Println(fi.Name())

        // 打开文件
        fr, err := os.Open(dir.Name() + "/" + fi.Name())
        if err != nil {
            panic(err)
        }
        defer fr.Close()

        // 信息头
        h := new(tar.Header)
        h.Name = fi.Name()
        h.Size = fi.Size()
        h.Mode = int64(fi.Mode())
        h.ModTime = fi.ModTime()

        // 写信息头
        err = tw.WriteHeader(h)
        if err != nil {
            panic(err)
        }

        // 写文件
        _, err = io.Copy(tw, fr)
        if err != nil {
            panic(err)
        }
    }
    fmt.Println("tar.gz ok")
}

总结核心代码:

python:

// 创建tar.gz
t = tarfile.open(fname + ".tar.gz", "w:gz")
// tar里添加文件
t.add(fiepath)

go:

// 创建tar.gz
fw, err := os.Create("tar/lin_golang_src.tar.gz")
gw := gzip.NewWriter(fw)
tw := tar.NewWriter(gw)
// 往tar里添加文件
fr, err := os.Open(filepath)
_, err = io.Copy(tw, fr)

可以看到:

  1. python封装了做tar的所有细节(创建tar并gzip压缩),而golang没有封装细节,要自己依次创建一个文件,带给gzip,再将gzip的输出带给tar。

    1. 创建tar.gz:python只需要调用tarfile包自己的方法open即可,而golang分3步,先os.Create获得fw,再把fw带到gzip.NewWriter获得gw,再把gw带到tar.NewWriter获得tw

    2. 往tar里添加文件:python只需要调用tarfile包自己的方法add即可,而golang分2步,首先是通过os.Open(公共方法)获得文件句柄,再把文件句柄带到io.Copy(公共方法)来处理

  2. 由于go语言的接口特点,golang没有必要像python一样完全封装细节,而是使用公共接口(每个类型都实现了相同的接口)

Note

当然用golang自己可以再做一次封装,比如自己也搞个tarfile包,封装创建tar和gzip压缩方法

详细剖析上面的tar.gz例子,详见golang-targz脑图(点击下载,并使用iThoughtsX打开)