douti9286 2017-08-25 18:56
浏览 36
已采纳

使用initilzer函数创建的结构不会导出到测试包中?

Say we have a struct and a constructor function for the structure like such

package myPackage

type Client struct {
    a TypeA
    b TypeB
}

func NewClient(a TypeA, b TypeB) ConcreteClient {
    return &Client{
        a: a,
        b: b,
    }
}

type ConcreteClient interface {
    ExportedFunc()
}

func (c *Client) privateFunc() {
    // ...
}

func (c *Client) ExportedFunc() {
    // ...
}

And we use this client in a test package like such

var (
    c = &Client {
        a:a,
        b:b,
    }
)

func TestUnexported(t *testing.T) {
    c.privateFunc() // Works
}

In the previous case the unexported is discovered as expected in the test file but when we use the constructor like this

var (
    c = NewClient()
)

func TestUnexported(t *testing.T) {
    c.privateFunc() // Doesn't work
}

The unexported method isn't exposed for testing. These files exist within the same package and follow the *_test naming pattern.I haven't been able to figure out exactly what is going on scoping wise as to why the unexported methods are hidden when created through a constructor and not through typical construction.

  • Edited for clarity
  • 写回答

1条回答 默认 最新

  • dousi4900 2017-09-01 08:44
    关注

    When you return a type as an interface or accept an interface in a function, then the type is reduced to only the methods in that interface and everything else will be inaccessible. You've effective "converted" the type from Client to ConcreteClient.

    Consider how the code would look if all methods from all types be readily accessible:

    func f(fp io.Reader) {
        fp.Seek(42)
    }
    

    How annoying would such a function be to use: "you can pass any io.Reader to this, but oh, it must also have the Seek() method or you'll get compile errors".

    This is why additional interfaces such as io.ReadSeeker (which has Read() and Seek()) exist.


    Not all is lost, you can still use access everything from the type methods:

    func (c *Client) ExportedFunc() string {
        return c.a
    }
    
    func main() {
        cclient := NewClient("this is a", "this is b")
        fmt.Printf(cclient.ExportedFunc())
    }
    

    Or you can use a type assertion to get the original type back:

    cclient := NewClient("this is a", "this is b")
    client, ok := cclient.(*Client)
    if !ok {
        fmt.Printf("not a Client: %T
    ", cclient)
        os.Exit(1)
    }
    fmt.Printf("a: %v
    ", client.a)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度