I've been reading a book about Golang and it's common use global vars to expose the result of private functions. Why not to expose public functions? here's an exemple.
I am comming from java and this is tricky for me. What are advantages of using global vars like these?
EDIT: I notice that without parenthesis I am not calling the function. It's just a pointer. Is it a good pratice or does have some advantages?
package config
import "time"
var (
GetHTTPServerAddress = getHTTPServerAddress
GetHTTPReadTimeout = getHTTPReadTimeout
GetHTTPWriteTimeout = getHTTPWriteTimeout
)
func getHTTPServerAddress() string {
return getConfigString("http.server_address")
}
func getHTTPReadTimeout() time.Duration {
return getConfigDuration("http.read_timeout")
}
func getHTTPWriteTimeout() time.Duration {
return getConfigDuration("http.write_timeout")
}
I've been reading a book about Golang and it's common use global vars to expose the result of private functions.
To expose the result of private functions, not the functions themselves; your example is a little off. Without the parens you're exposing the function itself.
package main
import (
"fmt"
)
var(
FooItself = foo // (func() string)(0x108b720)
FooResult = foo() // "bar"
)
func main() {
fmt.Printf("%#v\n", FooItself)
fmt.Printf("%#v\n", FooResult)
}
func foo() string {
return "bar"
}
Try it.
Your example would look more like this.
package config
var (
// You wouldn't call the variable "Get*", that exposes
// the implementation.
HTTPServerAddress = getHTTPServerAddress()
HTTPReadTimeout = getHTTPReadTimeout()
HTTPWriteTimeout = getHTTPWriteTimeout()
)
func getHTTPServerAddress() string {
return getConfigString("http.server_address")
}
func getHTTPReadTimeout() time.Duration {
return getConfigDuration("http.read_timeout")
}
func getHTTPWriteTimeout() time.Duration {
return getConfigDuration("http.write_timeout")
}
But no private methods are necessary. Just run the function and assign it to a global.
package config
var (
HTTPServerAddress = getConfigString("http.server_address")
HTTPReadTimeout = getConfigDuration("http.read_timeout")
HTTPWriteTimeout = getConfigDuration("http.write_timeout")
)
Now people can use config.HTTPServerAddress and the details remain hidden without requiring an extra layer of methods.
And yes, it can be done on the result public functions. A very common example is error codes. For example, in net/http.
var (
ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
ErrHijacked = errors.New("http: connection has been hijacked")
)
In Java you might create an exception subclass for each type of error. In Go you make a single object, share it as a global variable, and everything references that object.
The purpose is to hide the details from the user. The exact wording of the error can change, but as long as everyone is referencing net.http.ErrBodyNotAllowed their code will still work.
io/fs has a more complex example exposing the result of its private methods.
var (
ErrInvalid = errInvalid() // "invalid argument"
ErrPermission = errPermission() // "permission denied"
ErrExist = errExist() // "file already exists"
ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed"
)
func errInvalid() error { return oserror.ErrInvalid }
func errPermission() error { return oserror.ErrPermission }
func errExist() error { return oserror.ErrExist }
func errNotExist() error { return oserror.ErrNotExist }
func errClosed() error { return oserror.ErrClosed }
Why use private method wrappers here? Why not ErrInvalid = oserror.ErrInvalid?
(I'm assuming) Go wants to keep oserror hidden, even from the documentation!
oserror is just making error objects to define its possible errors.
package oserror
import "errors"
var (
ErrInvalid = errors.New("invalid argument")
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
ErrClosed = errors.New("file already closed")
)
If it's result of a function, it's probably something like static member initialization or perhaps even static final.
The example you linked suggests that it's some sort of config load procedure and values are exposed for global use.
Precomputing data is also not unheard of.
If you see function pointers, however, it could be done to enable mocking.
YMMV. Sometimes it's just an antipattern as well.
Related
I'm trying to extend fyne widget to have a simple clickable content with background.
I searched fyne widgets to find an example that could be used as a starter and found something similar in List/ListItem.
I basically copied the list item code and adapted it a little bit.
It does look similar to the simpler example on fyne documentation.
But for some unknown reason go gives me an error and I don't know what the cause is or how I can fix it:
custom_widget/simple_card.go:80:24: c.card.super undefined (type *SimpleCard has no field or method super)
Here is the code of the module (custom_widget/simple_card.go):
package custom_widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"log"
)
// Declare conformity with interfaces.
var _ fyne.Widget = (*SimpleCard)(nil)
var _ fyne.Tappable = (*SimpleCard)(nil)
type SimpleCard struct {
widget.BaseWidget
onTapped func()
background *canvas.Rectangle
content fyne.CanvasObject
selected bool
}
func NewSimpleCard(content fyne.CanvasObject, tapped func()) *SimpleCard {
card := &SimpleCard{onTapped: tapped, content: content}
card.ExtendBaseWidget(card)
return card
}
// CreateRenderer is a private method to Fyne which links this custom_widget to its renderer.
func (c *SimpleCard) CreateRenderer() fyne.WidgetRenderer {
c.ExtendBaseWidget(c)
c.background = canvas.NewRectangle(theme.SelectionColor())
c.background.Hide()
objects := []fyne.CanvasObject{c.background, c.content}
// NewBaseRenderer and BaseRenderer are copied from
// https://github.com/fyne-io/fyne/blob/master/internal/widget/base_renderer.go
// because the functionality is marked internal in fyne !?
return &SimpleCardRenderer{NewBaseRenderer(objects), c}
}
func (c *SimpleCard) Tapped(_ *fyne.PointEvent) {
log.Println("I have been tapped")
if c.onTapped != nil {
c.selected = true
c.Refresh()
c.onTapped()
}
}
// Declare conformity with the WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*SimpleCardRenderer)(nil)
type SimpleCardRenderer struct {
BaseRenderer
card *SimpleCard
}
// MinSize calculates the minimum size of a SimpleCardRenderer.
// This is based on the size of the status indicator and the size of the child object.
func (c *SimpleCardRenderer) MinSize() fyne.Size {
return c.card.content.MinSize()
}
// Layout the components of the SimpleCardRenderer custom_widget.
func (c *SimpleCardRenderer) Layout(size fyne.Size) {
c.card.background.Resize(size)
c.card.content.Resize(size)
}
func (c *SimpleCardRenderer) Refresh() {
if c.card.selected {
c.card.background.FillColor = theme.SelectionColor()
c.card.background.Show()
} else {
c.card.background.Hide()
}
c.card.background.Refresh()
canvas.Refresh(c.card.super()) // compiler error !
}
Remove all of the renderer type you created and in the CreateRenderer just return widget.NewSimpleRenderer(container .NewMax(c.background, c.content)). It is simpler than you think.
Copying code out of the main widgets is often not the best way as we have shortcuts and/or must support more functionality than your own widgets.
I used the github.com/hooklift/gowsdl/soap , and I got generated code with this pattern
package funky
import (
"fmt"
)
type Place struct {
Text string
}
type RandomFunky interface {
Buggy(b int)(int)
}
type randomFunky struct {
place *Place
}
func NewFunky(p *Place) RandomFunky {
return &randomFunky{
place: p,
}
return nil
}
func (rf * randomFunky) Buggy(b int)(int) {
fmt.Println(rf.place.Text)
return b
}
package main
import (
"fmt"
"funky"
)
func main() {
p := funky.Place{}
p.Text = "o jee"
f := funky.NewFunky(&p)
fmt.Printf("%T\n",f) // type of "*funky.randomFunky"
// var f *funky.randomFunky !!! cannot refer to unexported name funky.randomFunky
f.Buggy(1)
}
"f" - I can get this type this way, but I can not create a var of this type!
What if I want to store *funky.randomFunky var in the struct ?
Or pass it to the function?
Is this implies that I always have to recreate NewFunky every time I want to call Buggy method?
(assuming Buggy called in multiple places and/or interface has more methods)
Or should I modify the code and make *funky.randomFunky public?
Or else?
So the idea is that any variable/function/type/method starting with lowercase is local, and starting with uppercase is global. Local stuff can be used directly only inside the same package.
So in your case, RandomFunky is a global interface with a single method Buggy, and a randomFunky is a local structure, implementing RandomFunky, because it has the method Buggy with the same parameters.
In fact, NewFunky returns you a structure wrapped into an interface. So you can't use randomFunky outside the package funky, but you can use funky.RandomFunky.
In your case you can just create a variable of this type
...
var f funky.RandomFunky
f = funky.NewFunky(&p)
...
I know there are lots of other questions like this but they are all about calling a function from a main.go, which is not my case. In file1.go I have a function like this:
func (c *cubicSender) InRecovery() bool {
return c.largestAckedPacketNumber <= c.largestSentAtLastCutback && c.largestAckedPacketNumber != 0
}
func (c *cubicSender) InSlowStart() bool {
return c.GetCongestionWindow() < c.GetSlowStartThreshold()
}
I want to assign these functions into variables IR and ISS in file2.go. So when a function is called:
if IR == true {
fmt.Println(pathID, pth.sentPacketHandler.GetCongestionWindow(), pth.sentPacketHandler.GetBytesInFlight(), pth.rttStats.SmoothedRTT(), time.Now().UnixNano(), "SS")
} else if ISS == true {
fmt.Println(pathID, pth.sentPacketHandler.GetCongestionWindow(), pth.sentPacketHandler.GetBytesInFlight(), pth.rttStats.SmoothedRTT(), time.Now().UnixNano(), "IR")
}
How can I do that?
*Edit: I have imported the package, which has file1.go in file2.go.
InRecovery seems to be declared as a method of *cubicSender, not as a function. You cannot call methods just by specifying the package in which they are declared, you need an instance of the type on which the method is declared and then you can call the method by qualifying it with the instance variable's name.
Note that if you want to use the method InRecovery outside of the package in which it is declared, then you need to either export the type on which the method is defined (i.e. cubicSender), or you need to somehow provide access to an instance of the unexported type, e.g. via an exported variable, or function.
For example in congestion/file1.go:
package congestion
type cubicSender struct {
// ...
}
// exported function to provide access to the unexported type
func NewCubicSender() *cubicSender {
return &cubicSender{
// ...
}
}
func (c *cubicSender) InRecovery() bool {
return false
}
And in quic/file2.go:
package quic
import "path/to/congestion"
func foobar() {
c := congestion.NewCubicSender() // initialize an instance of cubicSender
if c.InRecovery() { // call InRecovery on the instance
// ...
}
}
I am junior Swift user but on this stage of life I need use serial connection in my project.
when I looking for availeble port ,I see them without problem but when try to send something I have problem why?
I have problem with ORSSerial this my code:
func applicationDidFinishLaunching(_ aNotification: Notification) {
let portEvString = ORSSerialPortManager.shared().availablePorts
let pathString = portEvString[0].path
let portClass = SerialController(path:pathString)
portClass.open()
portClass.SendString(data: "hello")
// Insert code here to initialize your application
RunLoop.current.run()
}
class SerialController : NSObject, ORSSerialPortDelegate {
var port : ORSSerialPort?
init(path: String){
port = ORSSerialPort(path: path)
port?.close()
}
func open(){
port?.baudRate=9600
port?.delegate=self
port?.open()
}
func close(){
port?.delegate=nil
port?.close()
}
func SendString(data: String){
let dataa = Data(data.utf8)
port?.send(dataa)
}
func serialPortWasOpened(serialPort: ORSSerialPort!) {
print("PORT IS OPEN....")
}
func serialPortWasClosed(serialPort: ORSSerialPort!) {
print("PORT IS CLOSE")
}
func serialPort(serialPort: ORSSerialPort!, didReceiveData data: NSData!) {
print(NSString(data: data as Data, encoding: String.Encoding.utf8.rawValue))
}
func serialPortWasRemovedFromSystem(_ serialPort: ORSSerialPort!) {
print("PORT REMOVED")
}
func serialPort(serialPort: ORSSerialPort!, didEncounterError error: NSError!) {
print("PORT ERR \(error)")
}
}
I believe the primary problem is that you don't store the instance of SerialController in a strong reference, so it gets deallocated immediately after you call SendString() on it. You need to store it in a property like so:
var serialController: SerialController?
func applicationDidFinishLaunching(_ aNotification: Notification) {
let availablePorts = ORSSerialPortManager.shared().availablePorts
let pathString = availablePorts[0].path
serialController = SerialController(path:pathString)
serialController?.open()
serialController?.SendString(data: "hello")
}
Beyond that problem, there are a number of things about this code that you should fix. The things that stick out most:
Don't call RunLoop.current.run() in applicationDidFinishLaunching(_:). You rarely need to manually run the run loop, and you definitely don't need to here.
As documented in ORSSerialPort, you must release any strong references to the port in your implementation of serialPortWasRemovedFromSystem(_:). That means in that method, you need to do port = nil.
The force unwrap operators (!) scattered through this code make me wonder if you're using an old version of ORSSerialPort, from before I added nullability annotations. Please make sure you're using the latest version (2.0.2 as of this writing).
Use more descriptive names for your variables. For example, portEvString is not a good name, because it's difficult to understand (what does "Ev" mean?), and its type is not a string, it's an array of ORSSerialPort objects (ie. [ORSSerialPort].
Your SendString method shouldn't start with a capital letter. Function (and method) names in Swift should always start with a lowercase letter.
After the disable SandBox, everything is OK.
When compiling the following Swift code (in Sample.swift):
import Cocoa
class Sample {
func doSomething() {
var stringArray = Array<String>()
stringArray.append("AAA")
addToString(stringArray)
stringArray.append("CCC")
}
func addToString(myArray:Array<String>) {
myArray.append("BBB")
}
}
I get the following error on the line 'myArray.append("BBB")':
Immutable value of type 'Array<String>' only has mutating members named 'append'
How do I fix the code to allow a call to this mutable method?
Many thanks in advance
If you want to modify the array you have to specify it as in an inout parameter like this func addToString(inout myArray:Array<String>). Then when you call the function you have to add & in front of your argument to show that it can be modified by the function. Your code will look something like this:
class Sample {
func doSomething() {
var stringArray = Array<String>()
stringArray.append("AAA")
addToString(&stringArray)
stringArray.append("CCC")
}
func addToString(inout myArray:Array<String>) {
myArray.append("BBB")
}
}
You may want to take a look at in-out parameters on this page.