Go – Idiomatic way around interface slice issue

huangapple go评论147阅读模式
英文:

Go - Idiomatic way around interface slice issue

问题

我有一个包含有关某人工作时间的 WorkDay 结构体,一个用于保存一组 WorkDay 的 WorkWeek 结构体,以及一个用于保存一组 WorkWeek 的 WorkMonth 结构体。每个结构体都返回在该时间段内工作的总小时数。

这段代码运行得很好,但是在 WorkWeek.HoursWorked()WorkMonth.HoursWorked() 中的重复代码真的让我很烦。我尝试了以下方法,以为自己非常聪明:

  1. func (w WorkWeek) HoursWorked() time.Duration {
  2. return sumHoursWorked(w.WorkDays)
  3. }
  4. func (m WorkMonth) HoursWorked() time.Duration {
  5. return sumHoursWorked(m.WorkWeeks)
  6. }
  7. type countable interface {
  8. HoursWorked() time.Duration
  9. }
  10. func sumHoursWorked(timeFrames []countable) time.Duration {
  11. var totalHours time.Duration
  12. for _, frame := range timeFrames {
  13. totalHours += frame.HoursWorked()
  14. }
  15. return totalHours
  16. }

然而,正如这里所解释的那样,尽管 WorkDay 实现了 countable 接口,但 WorkDay 的切片并不被视为 countable 的切片。

所以,有没有一种巧妙、惯用的方法可以解决这个问题,还是我只能接受重复代码呢?

英文:

I have a WorkDay struct holding data about the times someone worked, a WorkWeek struct to hold a bunch of WorkDays, and a WorkMonth struct to hold a bunch of WorkWeeks. The idea is to have each return the total hours worked during that period.

  1. type WorkDay struct {
  2. StartTime time.Time
  3. EndTime time.Time
  4. }
  5. type WorkWeek struct {
  6. WorkDays []WorkDay
  7. }
  8. type WorkMonth struct {
  9. WorkWeeks []WorkWeek
  10. }
  11. func (w WorkDay) HoursWorked() time.Duration {
  12. // Find hours worked through simple subtraction.
  13. }
  14. func (w WorkWeek) HoursWorked() time.Duration {
  15. var totalHours time.Duration
  16. for _, day := range w.WorkDays {
  17. totalHours += day.HoursWorked()
  18. }
  19. return totalHours
  20. }
  21. func (w WorkMonth) HoursWorked() time.Duration {
  22. var totalHours time.Duration
  23. for _, week := range w.WorkWeeks {
  24. totalHours += week.HoursWorked()
  25. }
  26. return totalHours
  27. }

This code works just fine, but the duplication in WorkWeek.HoursWorked() and WorkMonth.HoursWorked() really grinds my gears. I tried to do the following, thinking I was very clever:

  1. func (w WorkWeek) HoursWorked() time.Duration {
  2. return sumHoursWorked(w.WorkDays)
  3. }
  4. func (m WorkMonth) HoursWorked() time.Duration {
  5. return sumHoursWorked(m.WorkWeeks)
  6. }
  7. type countable interface {
  8. HoursWorked() time.Duration
  9. }
  10. func sumHoursWorked(timeFrames []countable) time.Duration {
  11. var totalHours time.Duration
  12. for _, frame := range timeFrames {
  13. totalHours += frame.HoursWorked()
  14. }
  15. return totalHours
  16. }

However, as explained here, even though WorkDay implements countable, a slice of WorkDays does not count as a slice of countables.

So, is there some nifty, idiomatic way out of this situation that I'm missing, or am I just stuck with the duplication?

答案1

得分: 4

不。要么使用countables的一部分来实现动态方法调度,或者进行一些编程(你的第一个解决方案),要么重新构建你的类型。我不了解你的问题领域,但是由周组成的月份似乎很奇怪,至少是月份/周的部分。

英文:

No. Either have a slice of countables which gives you dynamic method dispatch or some programming (your first solution) or restructure your types. I have no idea of your problem domain but months consisting of weeks consisting of days seems odd, at least the month/week stuff.

答案2

得分: 2

不,因为countables的切片是另一种类型。
你可以定义自己的切片类型,并将一个Add方法附加到它上面。

  1. func (w WorkWeek) HoursWorked() time.Duration {
  2. return sumHoursWorked(w.WorkDays)
  3. }
  4. func (m WorkMonth) HoursWorked() time.Duration {
  5. return sumHoursWorked(m.WorkWeeks)
  6. }
  7. type countable interface {
  8. HoursWorked() time.Duration
  9. }
  10. type SliceCountable []countable
  11. func (m *SliceCountable) Add(c countable) {
  12. *m = append(*m, c)
  13. }
  14. func (m SliceCountable) HoursWorked() time.Duration {
  15. var totalHours time.Duration
  16. for _, frame := range m {
  17. totalHours += frame.HoursWorked()
  18. }
  19. return totalHours
  20. }
  21. func sumHoursWorked(timeFrames []countable) time.Duration {
  22. var totalHours time.Duration
  23. for _, frame := range timeFrames {
  24. totalHours += frame.HoursWorked()
  25. }
  26. return totalHours
  27. }
英文:

No because slice of countables is another type.
You could define your own slice type and attach an Add method to it.

  1. func (w WorkWeek) HoursWorked() time.Duration {
  2. return sumHoursWorked(w.WorkDays)
  3. }
  4. func (m WorkMonth) HoursWorked() time.Duration {
  5. return sumHoursWorked(m.WorkWeeks)
  6. }
  7. type countable interface {
  8. HoursWorked() time.Duration
  9. }
  10. type SliceCountable []countable
  11. func (m *SliceCountable) Add( c countable ) {
  12. *m = append(*m, c )
  13. }
  14. func (m SliceCountable) HoursWorked() time.Duration {
  15. var totalHours time.Duration
  16. for _, frame := range m {
  17. totalHours += frame.HoursWorked()
  18. }
  19. return totalHours
  20. }
  21. func sumHoursWorked(timeFrames []countable) time.Duration {
  22. var totalHours time.Duration
  23. for _, frame := range timeFrames {
  24. totalHours += frame.HoursWorked()
  25. }
  26. return totalHours
  27. }

huangapple
  • 本文由 发表于 2014年5月22日 18:27:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/23804213.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定