Golang如何写出优雅代码入门

本文已被阅读过 Posted by 陌无崖 on 2019-08-20

导语

什么样的代码,才算优雅的代码,身为程序员,写代码就像写文章,写出好的文章不仅自己读着赏心悦目,同时也会让读者受到启发。然而事实上,大多数我们去回顾或者维护我们之前的代码,浮现在你眼前的是对自己代码的厌恶,会严重怀疑当时写这些代码时,大概是脑子进了水。那么该如何写好的优雅的代码?

Hello World

我们仍然从最简单的开始,编写一个hello函数

1
2
3
func Hello(name string) string {
return "Hello," + name
}

现在我们进行需求变更,我们希望用不同的语言发送hello…

1
2
3
4
5
6
7
8
9
10
func Hello(name string, language string) string {
if language == "Franch" {
return "用Franch进行问好:Hello," + name
} else if language == "English" {
return "用English进行问好:Hello," + name
} else if language == "Spanish" {
return "用Spanish进行问好:Hello," + name
}
return "hello," + name
}

我们暂时只用这个例子,想一下,如果我们的语言非常多,我们将会出现很多if else的语句,而且我们也发现在返回数据时,有一些前缀,我们是否可以将这些统一进行变量进行更好的管理呢?因此我们需要用到switch语句。
首先需要定义前缀

1
2
3
4
5
6
7
8
9
const (
frenchHelloPrefix = "用Franch进行问好:"
englishHelloPrefix = "用English进行问好:"
SpanishHelloPrefix = "用Spanish进行问好:"
common = "Hello,"
English = "English"
Franch = "Franch"
Spanish = "Spanish"
)

重新修改我们的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func Hello(name string, language string) string {
prefix := ""
switch language {
case Franch:
prefix = frenchHelloPrefix
case English:
prefix = englishHelloPrefix
case Spanish:
prefix = SpanishHelloPrefix
default:
prefix = ""
}
return prefix + common + name
}

这样我们很轻易的对我们的整体的思路进行了很好的组织,在case中只是专注了前缀,只用一个return返回结果便能达到我们的要求,并且我们的代码阅读时也会更加显得简洁。

type类型的巧妙使用

反面案例

首先需要明确我们的需求,我们将会定义一个钱包,实现存钱和取钱
首先定义一个结构体

1
2
3
type Wallet struct {
balance int
}

存钱

1
2
3
func (w *Wallet) Deposit(amount int) {
w.balance += amount
}

取钱

1
2
3
4
5
6
7
func (w *Wallet) Withdraw(amount int) error {
if amount > w.balance {
return errors.New("cannot withdraw, insufficient funds")
}
w.balance -= amount
return nil
}

上面是一个非常简单的程序,但是却有一个缺点,在现实生活中,我们的钱包里面是什么样的呢?除了现金,我们也存了各种银行卡,如何才能准确的定义这些属性呢?可能有的同学会按照下面的格式进行定义。

1
2
3
4
5
6
type Wallet struct {
balance int //零钱
creditbalance int //信用卡
Bankbalance int //银行卡

}

然后我们或许会猜到,他将会定义三个存储的函数进行存钱,是这样的

1
2
3
4
5
6
7
8
9
func (w *Wallet) Deposit(amount int) {
w.balance += amount
}
func (w *Wallet) Depositcreditbalance (amount int) {
w.creditbalance += amount
}
func (w *Wallet) DepositBankbalance (amount int) {
w.Bankbalance += amount
}

这些代码看起来“简洁”大概是因为少吧,如果说在真正存钱时会出现验证,转账,等这些大概就不能称之为简洁了,代码中将会出现大量重复的代码那应该怎么改呢?

正面案例

我们需要为我们的各种类型重新定义变量,像这样

1
2
3
type coin int
type creditCard int
type BankCard int

有了这些类型,我们需要存钱是指定我们的类型所有我们同样也需要定义一些常量

1
2
3
4
const (
CREDITCARD = "creditCard"
BANKCARD = "BankCard"
)

编写我们的函数

1
2
3
4
5
6
7
8
9
10
func (w *Wallet) Deposit(amount int, card string) {
switch card {
case CREDITCARD:
w.creditbalance += creditCard(amount)
case BANKCARD:
w.Bankbalance += BankCard(amount)
default:
w.balance += coin(amount)
}
}

这样我们只用了一个函数就完成了需求,同时逻辑因为有了变量也变得更加的清晰,代码也会给人一种阅读文章的感觉。
现在我们写一个取钱的函数,我们需要注意取钱时需要注意总金额不能超出金额的取钱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func (w *Wallet) Withdraw(amount int, card string) error {
switch card {
case CREDITCARD:
if creditCard(amount) > w.creditbalance {
return InsufficientFundsError
}
w.creditbalance -= creditCard(amount)
case BANKCARD:
if BankCard(amount) > w.Bankbalance {
return InsufficientFundsError
}
w.Bankbalance -= BankCard(amount)
default:
if coin(amount) > w.balance {
return InsufficientFundsError
}
w.balance += coin(amount)
}
return nil
}

以上需要注意的是,在返回错误时,我同样定义了一个变量,这样做的好处是,将来如果错误的类型较多,我们可以提前预制好一些错误信息,进行返回,然后统一放在一个文件中,使用的时候,直接调用,修改的时候也会方便查找。在这里我的定义如下:

1
var InsufficientFundsError = errors.New("超出了总金额")

总结

当然除了以上的代码习惯,或许也有更好的方式,都在与平时写代码时多思考,多参考,多积累。我们的代码才会写的越来越好,以上的总结是我今天在学习测试驱动开发时的突然的代码启发,整理成的笔记。因为测试驱动前面的基础比较简单,等到我学到后面的,再总结分享。

推荐阅读


本文欢迎转载,转载请联系作者,谢谢!


打开微信扫一扫,关注微信公众号