原本在回来路上想了好多,结果真要落笔的时候语塞了。。。
1. 函数
函数是结构化编程中最小的模块单元。
利用函数可以完成某种操作,实现某个目的。
2. 类
为了区分,把函数(function)、变量(variable)放到了类(class)里,其术语就改称方法(method)、属性(attribute)
类是对现实生活中一类具有共同特征的事物的抽象。
这句话对初学者而言很难理解,太学术了。其实就是把一堆变量、函数归类在一个名义之下。
-
比如
读取数据 read()
、插入数据 insert()
、修改数据 update()
、删除数据delete()
、数据库连接 conn
、表名 table
等都和数据库操作相关,那就把他们归在一起,并且命名为db
,调用的时候用db.insert()
、db.update()
、db.table
即可,这样开发时就很好理解这些方法是谁的、他能干嘛~~ -
比如对文件的操作也有类似数据库操作的方法,那么把这些方法、属性归在
file
这个类下,file.insert()
、file.update()
、file.delete()
、file.name
。
但是,但是,但是 ~~ go语言没有类。
好在go用了一个手段来实现我们一般理解的类,那就是在函数前挂一个变量。
- 其它语言是设定一个类,这个类包裹着所有方法;
- go语言是设定一个变量,把所有的函数挂在这个个变量下(这个变量就相当于类名,函数变成了方法)。
类 = 变量*(函数1+函数2+函数3…)
type classA string
func (a classA)method(){
...
}
type classB struct{
p1 string
p2 int
...
}
func (b classB)method1{
...
}
func (b classB)method2{
...
}
func main(){
// 这是最简单的一个“类”,只有方法method()
var a classA = "class"
a.method()
// 这个“类”里就有属性p1、p2,有方法method1()、method2()
var b classB = classB{p1:"param1",p2:"param2"}
b.method1()
b.method2()
}
3. 接口
接口有点类似于套娃最外一层。
接口是方法的抽象。
如果不同的类有同样的方法,那么就应该考虑使用接口。
上面说类的时候举过两个例子:数据库类db
和文件类file
。他们都有两个方法:修改 update()
、删除 delete()
,于是我们用一个叫做接口的东西,把同样的方法再归到一起。
比如我们设定一个叫做 data
的接口,把数据库和文件操作中的 update()
和 delete()
归到 data
之下,那么在使用的时候,无论是数据库还是文件,调用 data.update()
或data.delete()
即可(当然用之前得告知一下接口 data
,你是在操作数据库还是文件)。
接口 = 变量*(方法1+方法2+方法3)
下面示例里的局部变量为了看清楚,采用最复杂的写法,别打我~~哈哈
// 接口
type shower interface {
show(int)
}
// 结构体
type man struct {
name string
}
type woman struct {
name string
}
// 函数
func show(name string, age int) {
fmt.Println("姓名:", name, ",年龄:", age, ",性别:未知")
}
//方法
func (m man) show(age int) {
fmt.Println("姓名:", m.name, ",年龄:", age, ",性别:男")
}
func (w woman) show(age int) {
fmt.Println("姓名:", w.name, ",年龄:", age, ",性别:女")
}
// 使用
func main(){
// 调用函数
var name string = "王函数"
var age int = 18
show(name, age)
//调用方法
var m man = man{name: "Zhang Method"}
m.show(age)
var w woman = woman{name: "Lee Method"}
w.show(age)
//调用接口
var s shower
s = man{name: "シェンインターフェース"}
s.show(age)
s = woman{name: "チャプターインターフェース"}
s.show(age)
}
结果
函数:
姓名: 王函数 ,年龄: 18 ,性别:未知
方法:
姓名: Zhang Method ,年龄: 18 ,性别:男
姓名: Lee Method ,年龄: 18 ,性别:女
接口:
姓名: シェンインターフェース ,年龄: 18 ,性别:男
姓名: チャプターインターフェース ,年龄: 18 ,性别:女
4. 包
包是来组织源代码的,包(package)是多个 Go 源码的集合。
意味着变量、函数、方法、接口等等代码都可以塞进包package
里。实际使用时,有一些有趣的现象:
- 如果包里只有函数,那么这个包就相当于一个类了。
import "./db"
func main(){
// 像不像公有属性?
db.Table = "test"
// 像不像公有方法?
db.Add(db.Table)
}
- 不同文件都可以归在一个包下,只需要文件开头标识同一个包名,但是一个包内不能有重名变量、函数,那么同名怎么办呢?此时就可以用个标识加以区分,比如go提供了“方法”,在方法的开头带上一个“类”名,就可以了。
文件1: ./pkg/classa.go
package pkg // 包名pkg
type ClassA string // 类名
func (a ClassA)Method(){ // 方法
...
}
文件2: ./pkg/classb.go
package pkg // 包名pkg
type ClassB struct{}
func (b ClassB)Method(){
...
}
调用
package main
import "./pkg"
func main(){
var p pkg.ClassA = "A"
var q = new(pkg.ClassB)
p.Method()
q.Method()
}
5. 其它
?能不能不用类、接口
当然可以,用到类、接口只是为了便于开发,提高效率,提高理解。
如果不想用类、接口,也是可以的,只要你每个函数、变量都区分好。
比如数据库类里的方法,你只需要分别命名为db_insert()
、db_update()
、file_delete()
、file_update()
,看,是不是就可以了?
但是当你的项目越来越大,你会发现这样命名非常不方便,原因有很多,比如:没有归类,别扭;每次都要写全名,一个有变化,全都要改~~
?感觉包和接口很像啊
接口 则侧重于方法的抽象,方法的归纳,方法的使用;
包 更侧重于文件的分类,其包含的内容更丰富,一般同一个包的文件都放在一个目录里;
无论是哪种术语、命名、规则,其目的都是为了实现某种功能和需求,他们都仅仅是便于你开发的工具,而不是必需品。如果你能仅靠函数就完成所有开发,也不是不可以,只不过大项目的可读性、维护性、重复性太差罢了。