【问题标题】:Private fields and methods for a struct结构的私有字段和方法
【发布时间】:2014-04-04 13:58:57
【问题描述】:

在下面的测试代码中,我希望 mytypedoPrivate 方法都是私有的,这样只有 mytype 的成员可以访问它,但不能访问 @987654324 范围内的其他类型\函数@包。

我可以在 golang 中做到这一点吗?

package mypackage

type mytype struct {
    size          string
    hash          uint32
}

func (r *mytype) doPrivate() string {
    return r.size
}

func (r *mytype) Do() string {
    return doPrivate("dsdsd")
}

字段sizehash 以及doPrivate 方法应该被封装并且没有其他类型可以访问它们。

【问题讨论】:

    标签: go


    【解决方案1】:

    这不是“隐私”在 Go 中的工作方式:隐私的粒度就是包。

    如果您真的只希望mytype 的成员访问某些字段,那么您必须将结构和函数隔离在他们自己的包中。

    但这不是通常的做法。 Go 是否是 OOP 是有争议的,但显然这种做法并不是像你想要的那样用结构封装代码。通常一个包足够小以保持一致:如果您不想访问包内的字段,请不要访问它们。

    【讨论】:

    • 好吧,这很糟糕 :) 封装是现代编程的支柱之一。它将强制为每个“类”创建一个包。我想知道它背后的设计决策是什么。
    • 我建议你阅读一些主要的 Go 标准包的代码。是的,整包。您会惊讶于这种选择所带来的清晰性和简单性。不要试图在 Go 中模拟另一种语言。
    • 好点,我不喜欢也不理解为什么人们在 JavaScript 中模拟“类”或“经典继承”。在这个时间点上,它似乎是有线的。
    • 一句话,“如果你不想访问包中的字段,就不要访问它们”——你可以说一般的封装,但这不是解决任何问题。似乎 Golang 将抽象从类范围移动到包范围。在我看来,这可能会使程序难以维护。就像 JavaScript 中的模块(私有字段除外)。
    • 背后的隐含理由是,包足够简单且足够小,因此没有一致性问题,也不需要内部隐私强制。如果你觉得它更难维护,可能是你的包太大了。当然,我们在这里更关注的是意见和不同的程序员实践和经验。
    【解决方案2】:

    你不能在 Go 中做到这一点。可见性仅在每个包级别上。但是您可以将您的包裹分成两部分。

    【讨论】:

      【解决方案3】:

      在 Go 中,以大写字母开头的标识符从包中导出,并且声明它的包之外的任何人都可以访问。

      如果标识符以小写字母开头,则只能从包内访问。

      如果您需要某个类型中的成员只能由该类型的成员访问,则需要将该类型及其成员函数放在单独的包中,作为该包中的唯一类型。

      【讨论】:

        【解决方案4】:

        您可以使用您希望公开的方法创建一个接口,并且只有在包装到该接口时才能访问该对象。

        package main
        
        type mytype struct {
            size string
            hash uint32
        }
        
        // interface for exposed methods
        type myinterface interface {
            do() string
        }
        
        // constructor (optional)
        func newMytype(size string, hash uint32) myinterface {
            return &mytype{size, hash}
        }
        
        func (r *mytype) doPrivate() string {
            return r.size
        }
        
        func (r *mytype) do() string {
            return r.doPrivate()
        }
        
        func main() {
            // with constructor
            t := newMytype("100", 100)
            t.do()
            // t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)
        
            // without constructor
            t2:= myinterface(&mytype{"100", 100})
            t2.do()
            // t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)doPrivate)
        }
        

        https://play.golang.org/p/awjIIj8Kwms

        【讨论】:

        • 在所有答案中,这个结合了世界上最好的,应该更高。正确的编程确实涉及接口,因此更有理由使用它们。做得很好!
        【解决方案5】:

        在一个模块中可以有任意数量的包。

        Public/Private 仅适用于一个包。
        所有 public 字段、方法和函数都以 大写 字符开头。
        所有私有字段、方法和函数都以小写字符开头。

        要将包添加到您的模块或程序,只需创建一个小写文件夹并将包名称添加到其中的所有文件。这是一个例子。

        ./main.go
        ./foo/foo.go
        ./foo/MyStruct.go
        

        文件./foo/foo.go:

        package foo
        
        import "fmt"
        
        func SomePublicFuncInFoo() {
            somePrivateFuncInFoo()
        }
        
        func somePrivateFuncInFoo() {
            fmt.Println("somePrivateFuncInFoo call")
        }
        
        

        文件./foo/MyStruct.go:

        package foo
        
        import "fmt"
        
        type MyStruct struct {
            MyPublicField  string // starts with uppercase char
            myPrivateField string // starts with lowercase char
        }
        
        func NewMyStruct(publicField string, privateField string) *MyStruct {
            return &MyStruct{
                MyPublicField:  publicField,  
                myPrivateField: privateField, 
            }
        }
        
        func (self *MyStruct) SomePublicMethod() {
            self.privateMethod()
        }
        
        func (self *MyStruct) privateMethod() {
            fmt.Println("MyStruct", self.MyPublicField, self.myPrivateField)
        }
        
        

        文件./main.go:

        package main
        
        import (
            "fmt"
            "{your-module-name}/foo" // this line should be added by your IDE
        )
        
        func main() {
        
            foo.SomePublicFuncInFoo()
        
            myStruct := foo.NewMyStruct("string1", "string2")
            fmt.Println("myStruct.MyPublicField=", myStruct.MyPublicField)
        
            myStruct.SomePublicMethod()
        }
        

        【讨论】:

          猜你喜欢
          • 2011-08-05
          • 1970-01-01
          • 2020-12-04
          • 2013-09-01
          • 2020-08-03
          • 1970-01-01
          • 2013-05-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多