Let's start with three files.
src/logger/logger.go
src/chat_server/main.go
src/chat_server/sub/sub.go
logger.go
package logger import ( "fmt" ) type logger struct { Timestamp int } type Togger struct { Timestamp int } var log = logger{Timestamp: 12345} var Tog = Togger{Timestamp: 12345} func (l *logger)writeInfoFile(s string) { fmt.Println(s) } func (l *logger)writeErrorFile(s string) { fmt.Println(s) } func Debug(s string) { log.writeInfoFile(s) fmt.Println(&log.Timestamp) }
There is a logger object named log with a single timestamp field. The other thing to note is that the functions, variables and structs (golang's version of a class) can have an upper or lower case first letter.
"if something starts with a capital letter that means other packages (and programs) are able to see it" - http://www.golang-book.com/11/index.htm
For those us who are used to having public and private keywords in our OO language, this capital letter convention is how go restricts access. This means that Togger, Tog, and Debug() can be referred to once logger is imported in another file. While log, loger and write*() can not. This takes a little closer to our goal because we should be able to instantiate an instance of logger, and only allow specific functions to act on it.
main.go
package main import ( "logger" "chat_server/sub" "fmt" ) func main() { logger.Debug("one") logger.Debug("two") sub.CheckingAddress() isPublic := logger.Togger{Timestamp: 555} fmt.Println(isPublic.Timestamp) fmt.Println(logger.Tog.Timestamp) // These will cause an error // fmt.Println(logger.log.Timestamp) // isPublic := logger.logger{Timestamp: 333} }
Here are some examples of how this works. Debug is a function that can be accessed after the import. It can refer to var log as it's within the same package. Trying to access logger.log directly is not allowed, while the analagous struct value logger.Tog can be called. Any attempt to init a new 'logger' object also fails.
There is one more quick check that I wanted to verify and that is to confirm the log object continues to be the only instance no matter where it is imported.
sub.go
package sub import ( "logger" ) func CheckingAddress() { logger.Debug("In SUB") }
Way back in logger.go I print out the memory address of the Timestamp field.
fmt.Println(&log.Timestamp)
After running main, the output is:
one
0x547068
two
0x547068
In SUB
0x547068
555
12345
We get the same address so it's good.
Conclusion: I was able to create a single instance of my logger struct without resorting to a singleton and learned how go packages limit access to vars and and functions.
No comments:
Post a Comment