dongsou3041 2018-03-29 03:52
浏览 32

初始化多种资源并管理其寿命

Suppose you have to initialize a chain of resources in order to do something, typically with one initialization depending on the next. For example, you need to launch a browser, to open a browser window, to open a tab, to navigate that tab to a web site. At the end of the operation, you want to close or tear down every resource you have initialized.

Let's look at this naive code:

func main() {
  window, err := NewWindow()
  if err != nil {
    panic(err)
  }
  defer window.Close()

  tab, err := NewTab(window)
  if err != nil {
    panic(err)
  }
  defer tab.Close()

  NavigateToSite(tab)
}

(Of course, this code is pretty simple, so one might ask why ever refactor it, so keep in mind it's example's sake, and the actual chain of initializations might be longer and more convoluted.)

Suppose then I want to factor out the initialization, noticing that the actual logic in my code doesn't need the window at all. What would be an idiomatic way to do it? So far I can think of:

func main() {
  rs, err := NewMyResource()
  if err != nil {
     panic(err)
  }
  defer rs.Close()

  NavigateToSite(rs.Tab)
}

struct MyResource {
  Window *window;
  Tab *tab;
}

func NewMyResource() (*MyResource, error) {
  rs := &MyResource{}

  window, err := CreateWindow()
  if err != nil {
    rs.Close()
    return nil, err
  }
  rs.Window = window

  tab, err := CreateTab()
  if err != nil {
    rs.Close()
    return nil, err
  }
  rs.Tab := tab

  return rs, nil
}

func (rs MyResource) Close() {
  if rs.Window != nil {
    rs.Window.Close()
  }

  if rs.Tab != nil {
    rs.Tab.Close()
  }
}
  • 写回答

2条回答 默认 最新

  • doudouchan5830 2018-03-29 13:29
    关注

    A possible alternative (not necessarily better, it depends on context) might be to return a closure:

    func NewMyResource() (tab Tab, closer func(), err error) {
        var window Window
        window, err = NewWindow()
        if err != nil {
            return
        }
    
        tab, err = NewTab(window)
        if err != nil {
            return
        }
        closer = func() {
            tab.Close()
            window.Close()
        }
        return
    }
    

    Using it something like:

    tab, cl, err := NewMyResource()
    if err != nil {
        panic(err)
    }
    defer cl()
    

    I would generally go with the struct-based solution, but sometimes a new type is overkill and returning a function is easier.

    评论

报告相同问题?

悬赏问题

  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害