dongliang1893 2019-08-25 14:08
浏览 39

重用结构以减少堆使用

Please explain what is happening in following code. The part I don't understand is the service struct. The service struct is a wrapper around the APIClient struct. When the NewAPIClient is called, it is using the service struct inside and copying onto itself. I cannot seem to wrap my head around this. Please advise and elaborate. Thank you.

type APIClient struct {
    cfg    *Configuration

    // Reuse a single struct instead of 
    // allocating one for each service on the heap.
    common service 

    // API Services
    AccountApi          *AccountApiService
    ContractApi         *ContractApiService
    FYIApi              *FYIApiService
    IBCustApi           *IBCustApiService
    MarketDataApi       *MarketDataApiService
    OrderApi            *OrderApiService
    PnLApi              *PnLApiService
    PortfolioApi        *PortfolioApiService
    PortfolioAnalystApi *PortfolioAnalystApiService
    ScannerApi          *ScannerApiService
    SessionApi          *SessionApiService
    TradesApi           *TradesApiService
}

type service struct {    
    client *APIClient    
}

func NewAPIClient(cfg *Configuration) *APIClient {    
    if cfg.HTTPClient == nil {    
            cfg.HTTPClient = http.DefaultClient    
    }    

    c := &APIClient{}    
    c.cfg = cfg    
    c.common.client = c    

    c.AccountApi = (*AccountApiService)(&c.common)    
    c.ContractApi = (*ContractApiService)(&c.common)
    c.FYIApi = (*FYIApiService)(&c.common)
    c.IBCustApi = (*IBCustApiService)(&c.common)
    c.MarketDataApi = (*MarketDataApiService)(&c.common)
    c.OrderApi = (*OrderApiService)(&c.common)
    c.PnLApi = (*PnLApiService)(&c.common)
    c.PortfolioApi = (*PortfolioApiService)(&c.common)
    c.PortfolioAnalystApi = (*PortfolioAnalystApiService)(&c.common)
    c.ScannerApi = (*ScannerApiService)(&c.common)
    c.SessionApi = (*SessionApiService)(&c.common)
    c.TradesApi = (*TradesApiService)(&c.common)

    return c
}
  • 写回答

1条回答 默认 最新

  • dsgdg54ef4365 2019-08-25 15:53
    关注

    First, note that the expression (*AccountApiService)(&c.common) is an explicit conversion:

    A conversion changes the type of an expression to the type specified by the conversion.

    There is a number of rules that allow you to convert an expression of one type to another type, but the one relevant to your use case is this one:

    • ignoring struct tags (see below), x's type and T have identical underlying types.

    So the assignment statement c.AccountApi = (*AccountApiService)(&c.common) can be explained like this: Since the field common is of type service the expression &c.common is of type *service, that type is then converted to *AccountApiService and the result of that conversion expression is then assigned to the c.AccountApi field.

    And as we established above, for the conversion to work the two types, *AccountApiService and *service, must have the same underlying type. So, even though you haven't provided the definitions to any of those XxxApiService types, it is safe to assume that, if the code actually compiles, they are all defined as either

    type XxxApiService service
    

    or

    type XxxApiService struct {
        client *APIClient
    }
    

    effectively giving them the same underlying type as the service's underlying type.


    You may ask yourself why not initialize the various services like a normal person, why not write this

    c.AccountApi = &AccountApiService{c}
    

    instead? The answer to that is in the comment above the common field of APIClient.

    Reuse a single struct instead of allocating one for each service on the heap.

    Which means that instead of allocating a new instance of XxxApiService for each service field, the value allocated to common is shared by all of the service fields. The intent here, I assume, is resource/performance optimization.


    And finally the assignment c.common.client = c. The APIClient has a field named common of type service, and the type service has a field named client of type *APIClient. This basically allows a client to hold a reference to itself through the common field, which, although it's not the primary aim here, is exactly what is happening in the example code. Basically recursion, an unintended feature of the APIClient design AFAICT, but it is there.

    评论

报告相同问题?

悬赏问题

  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?
  • ¥15 matlab(相关搜索:紧聚焦)
  • ¥15 基于51单片机的厨房煤气泄露检测报警系统设计
  • ¥15 Arduino无法同时连接多个hx711模块,如何解决?