在 Go 中,如果一个符号(例如变量、类型、函数等)是以小写符号开头,那么它在 定义它的包之外 就是私有的。
在 Go 中,当调用一个函数或方法时,参数会被复制。
当调用 func (w Wallet) Deposit(amount int) 时,w 是来自我们调用方法的副本。
Go 允许从现有的类型创建新的类型。
类型别名有一个有趣的特性,你还可以对它们声明方法。当你希望在现有类型之上添加一些领域内特定的功能时,这将非常有用。
在类型别名上创建方法的语法与结构上的语法相同。
如果你看到一个函数,它接受参数或返回值的类型是接口,它们就可以是 nil。
指针
-
当你传值给函数或方法时,Go 会复制这些值。因此,如果你写的函数需要更改状态,你就需要用指针指向你想要更改的值
-
Go 取值的副本在大多数时候是有效的,但是有时候你不希望你的系统只使用副本,在这种情况下你需要传递一个引用。例如,非常庞大的数据或者你只想有一个实例(比如数据库连接池)
-
指针可以是 nil
-
当函数返回一个的指针,你需要确保检查过它是否为 nil,否则你可能会抛出一个执行异常,编译器在这里不能帮到你
-
nil 非常适合描述一个可能丢失的值
错误
-
错误是在调用函数或方法时表示失败的
-
通过测试我们得出结论,在错误中检查字符串会导致测试不稳定。因此,我们用一个有意义的值重构了,这样就更容易测试代码,同时对于我们 API 的用户来说也更简单。
-
错误处理的故事远远还没有结束,你可以做更复杂的事情,这里只是抛砖引玉。后面的部分将介绍更多的策略。
-
不要只是检查错误,要优雅地处理它们。
package main
import (
"errors"
"fmt"
)
//Bitcoin represents a number of Bitcoins
type Bitcoin int
func (b Bitcoin) String() string {
return fmt.Sprintf("%d BTC", b)
}
//Wallet stores the number of Bitcoin someone owns
type Wallet struct {
balance Bitcoin
}
//Deposit will add some Bitcoin to a wallet
func (w *Wallet) Deposit(amount Bitcoin) {
w.balance += amount
}
//ErrInsufficientFunds means a wallet does not have enough Bitcoin to perform a withdraw
var ErrInsufficientFunds = errors.New("cannot withdraw ,insufficient funds")
//Withdraw subtracts some Bitcoin from the wallet
func (w *Wallet) Withdraw(amount Bitcoin) error {
if amount > w.balance {
return ErrInsufficientFunds
}
w.balance -= amount
return nil
}
//Balance returns the number of Bitcoin a wallet has
func (w *Wallet) Balance() Bitcoin {
return w.balance
}
package main
import "testing"
func assertBalance(t *testing.T, wallet Wallet, want Bitcoin) {
t.Helper()
got := wallet.Balance()
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}
func assertNotError(t *testing.T, got error) {
t.Helper()
if got != nil {
t.Fatal("got an error but didnot want one")
}
}
func assertError(t *testing.T, got error, want error) {
t.Helper()
if got == nil {
t.Fatal("didn't get an error but wanted one")
}
if got != want {
t.Errorf("got '%s', want '%s'", got, want)
}
}
func TestWallet(t *testing.T) {
t.Run("Deposit", func(t *testing.T) {
wallet := Wallet{}
wallet.Deposit(Bitcoin(10))
assertBalance(t, wallet, Bitcoin(10))
})
t.Run("Withdraw with funds", func(t *testing.T) {
wallet := Wallet{balance: Bitcoin(20)}
err := wallet.Withdraw(10)
assertBalance(t, wallet, Bitcoin(10))
assertNotError(t, err)
})
t.Run("Withdraw insufficient funds", func(t *testing.T) {
startingBalance := Bitcoin(20)
wallet := Wallet{startingBalance}
err := wallet.Withdraw(Bitcoin(100))
assertBalance(t, wallet, startingBalance)
assertError(t, err, ErrInsufficientFunds)
})
}
网友评论