假设以最简单的加减乘除举例
type Money struct {
amount int64
currency string
}
想要实现
money.new(123.12, "USD").Add(456).Mul(123).toStr()
这里面,先初始化成 money ,然后做运算,最后 toStr 成科学计数法的格式。当然,每一步都可以拆开,比如先初始化,然后 add ,得到的 money 最后通过参数传给其他方法运行,在另外的方法里面可以继续计算或者格式化输出。
这里,new 可能报错,比如溢出、格式不正确,add 、mul 都有可能溢出。
如果是 java 来实现,可以很好的 try catch 包起来,但是放到 go 里面,因为只能通过 return value 来判断,感觉很难设计出都能兼容上面方式的代码。
要么就是在 tostr 最后计算的时候判断前面所有报错
if m, err := money.new(123.12, "USD"); err != nil {
m := m.Add(456).Mul(123)
if val, err := m.toStr(); err != nil {
...
}
}
要么就是每一步都判断,错误存入 money 对象中,需要的时候判断
m := money.new(123.12, "USD")
if Errors.isError(m) {
...
}
m := Add(456).Mul(123);
if Errors.isError(val) {
...
}
val := m.toStr()
if Errors.isError(val) {
...
}
or
val := money.new(123.12, "USD").Add(456).Mul(123).toStr()
if Errors.isError(val) {
...
}
刚学习 go ,希望能得到大家的一些中肯建议,感谢!
1
phpfpm 2023-07-10 16:23:36 +08:00
你最后加一个
```go money.new(123.12, "USD").Add(456).Mul(123).Done().toStr() ``` 有问题直接在 Done 那里 panic |
2
pota 2023-07-10 16:24:25 +08:00
if _, err := money.new(123.12, "USD").Add(456).Mul(123).toStr(); err != nil {
// 处理错误 } 每个方法返回结构体指针和 error 就行了啊。 |
3
picone 2023-07-10 16:26:53 +08:00
首先,Go 其实是希望每个错误都能处理。不过如果非要这么做,也不是不行,但是有点丑
```go import "fmt" type Money struct { Amount int64 Currency string LastError error } func (m Money)Add(val Money) Money { if m.LastError != nil || val.LastError != nil { return m } if m.Currency != val.Currency { m.LastError = fmt.Errorf("currency mismatch") return m } return Money{Amount: m.Amount + val.Amount, Currency: m.Currency} } func main() { a := Money{Amount: 100, Currency: "USD"} b := Money{Amount: 200, Currency: "USD"} c := Money{Amount: 200, Currency: "HKD"} fmt.Println(a.Add(b)) fmt.Println(a.Add(c)) } ``` |
4
lisxour 2023-07-10 16:30:36 +08:00
val, err := money.new(123.12, "USD").Add(456).Mul(123).toStr()
每个方法都进行单独的 error 捕捉,如果发生错误了存一个 lastError ,后续的方法判断之前是否有 lastError ,有就不做任何计算返回,最后的 toStr 就判断有没有 lastError ,有的话返回 nil, lastError ,否则返回 result, nil |
5
aapeli 2023-07-10 16:32:32 +08:00
推荐在最后一个函数返回错误, 如果中间状态时发现出错,则暂存错误.
``` val,err := money.new(123.12, "USD").Add(456).Mul(123).Done() if err != nil { } ``` 参考 gorm 的错误处理 https://gorm.io/zh_CN/docs/error_handling.html @dyingfire |
6
realpg 2023-07-10 16:47:01 +08:00
如果是 java 来实现,可以很好的 try catch 包起来,但是放到 go 里面,因为只能通过 return value 来判断,感觉很难设计出都能兼容上面方式的代码。
两个字:指针 |
7
yazinnnn 2023-07-10 16:58:16 +08:00
|
8
ryalu 2023-07-10 17:04:20 +08:00 1
go 1.20 加上了 errors.Join() 函数了 https://pkg.go.dev/errors#Join ,直接最后对错误做判断处理。1.19 之前可以使用 multierr.Combine(),import "go.uber.org/multierr"
|
9
SimbaPeng 2023-07-10 17:15:36 +08:00
|
10
xiangyuecn 2023-07-10 17:22:46 +08:00
惊呆了,这种语言上的设计,和 python 的缩进语法有的一拼,估计作者自己都吐了😂
|
11
FreeEx 2023-07-10 18:00:05 +08:00
你可以这样写
``` package main import "log" type OP string const ( Add OP = "add" Mul OP = "mul" ) type step struct { op OP value int64 } func NewMoney(amount int64) *Money { return &Money{ amount: amount, } } type Money struct { amount int64 steps []step } func (r *Money) Add(v int64) *Money { r.steps = append(r.steps, step{ op: Add, value: v, }) return r } func (r *Money) Mul(v int64) *Money { r.steps = append(r.steps, step{ op: Mul, value: v, }) return r } func (r *Money) Run() (int64, error) { for _, step := range r.steps { switch step.op { case Add: r.amount += step.value case Mul: r.amount -= step.value } } return r.amount, nil } func main() { val, err := NewMoney(123).Add(456).Mul(123).Run() if err != nil { log.Fatal(err) } log.Println(val) } ``` |
12
Kumo31 2023-07-10 18:21:44 +08:00
我会使用第一种,「错误是值」,在连续操作中错误不应该打断控制流,而是记录错误,最后再返回。典型例子是 Scanner 的设计:
```go scanner := bufio.NewScanner(input) for scanner.Scan() { token := scanner.Text() // process token } if err := scanner.Err(); err != nil { // process the error } ``` 官方 blog 有篇文章讲过这种设计模式: https://go.dev/blog/errors-are-values |
13
cnoder 2023-07-10 18:23:13 +08:00
不需要每个方法都执行,前面的可以只构建参数,只在某几个最后调用 exec 的方法里处理 类似 9 楼的方案
|
14
lc5900 2023-07-10 18:57:06 +08:00
可以参考下 gorm 的链式实现方式
|
15
lesismal 2023-07-10 22:13:14 +08:00
链式不直观清晰,不容易理解,链式本身就很丑。
总结:OP 什么破品味!少制造这种辣鸡封装! |
16
trzzzz 2023-07-10 23:52:34 +08:00
orm 和 httputil 中链式还是挺方便的
|
17
xuanbg 2023-07-11 08:24:04 +08:00
链式调用实在是丑得一逼!实现链式调用非常简单,每个方法都返回 this 就行。
|
18
proxytoworld 2023-07-11 10:25:15 +08:00
@xuanbg 那啥比较好看
|