Struct field not updated when implementing interface function - interface

If for example we have the following interface:
type IRoute interface {
AddChildren(child IRoute)
}
The following struct:
type Route struct {
Alias string `json:"alias"`
Children []Route `json:"children,omitempty"`
Url string `json:"url,omitempty"`
}
And implemented the interface:
func (this Route) AddChildren (child globals.IRoute){
this.Children = append(this.Children, child.(Route))
}
Then in our main func, if we wanted to test this it would not work:
rSettings := Route{"settings", nil, "/admin/settings"}
rSettingsContentTypesNew := models.Route{"new", nil, "/new?type&parent"}
rSettingsContentTypesEdit := models.Route{"edit", nil, "/edit/:nodeId"}
// Does NOT work - no children is added
rSettingsContentTypes.AddChildren(rSettingsContentTypesNew)
rSettingsContentTypes.AddChildren(rSettingsContentTypesEdit)
rSettings.AddChildren(rSettingsContentTypes)
And this does work as expected:
rSettings := Route{"settings", nil, "/admin/settings"}
rSettingsContentTypesNew := models.Route{"new", nil, "/new?type&parent"}
rSettingsContentTypesEdit := models.Route{"edit", nil, "/edit/:nodeId"}
// However this does indeed work
rSettingsContentTypes.Children = append(rSettingsContentTypes.Children,rSettingsContentTypesNew)
rSettingsContentTypes.Children = append(rSettingsContentTypes.Children,rSettingsContentTypesEdit)
rSettings.Children = append(rSettings.Children,rSettingsContentTypes)
What am I missing? :-)

The receiver of func (this Route) AddChildren (child globals.IRoute) is a value, so you are changing a copy of your Route struct.
Change it to func (this *Route) AddChildren (child globals.IRoute)

Related

bson.M {} deepequal does not seem to hande int32

I have a function for comparing two structs and making a bson document as input to mongodb updateOne()
Example struct format
type event struct {
...
Name string
StartTime int32
...
}
Diff function, please ignore that I have not checked for no difference yet.
func diffEvent(e event, u event) (bson.M, error) {
newValues := bson.M{}
if e.Name != u.Name {
newValues["name"] = u.Name
}
if e.StartTime != u.StartTime {
newValues["starttime"] = u.StartTime
}
...
return bson.M{"$set": newValues}, nil
}
Then I generated a test function like so:
func Test_diffEvent(t *testing.T) {
type args struct {
e event
u event
}
tests := []struct {
name string
args args
want bson.M
wantErr bool
}{
{
name: "update startime",
args: args{
e: event{StartTime: 1},
u: event{StartTime: 2},
},
want: bson.M{"$set": bson.M{"starttime": 2}},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := diffEvent(tt.args.e, tt.args.u)
if (err != nil) != tt.wantErr {
t.Errorf("diffEvent() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("diffEvent() = %v, want %v", got, tt.want)
}
})
}
}
This fails with a
--- FAIL: Test_diffEvent/update_startime (0.00s)
models_test.go:582: diffEvent() = map[$set:map[starttime:2]], want map[$set:map[starttime:2]]
For me this seem to be the same. I have played around with this and bool fields, string fields, enum fields, and fields as struct or fields as arrays of structs seems to work fine with deepequal, but it gives an error for int32 fields.
As a go beginner; what am I missing here? I would assume that if bool/string works then int32 would too.
This:
bson.M{"starttime": 2}
Sets the "starttime" key to the value of the literal 2. 2 is an untyped integer constant, and since no type is provided, its default type will be used which is int.
And 2 values stored in interface values are only equal if the dynamic value stored in them have identical type and value. So a value 2 with int type cannot be equal to a value 2 of type int32.
Use explicit type to tell you want to specify a value of int32 type:
bson.M{"starttime": int32(2)}

Slice index of variadic arguments

I am using PostgreSQL as a database for my service, with a go backend.
After querying the database, I can access the rows with rows.Next() and rows.Scan(XX) :
func All(receptacle ...interface{}) (error) {
[...]
for rows.Next() {
err = rows.Scan(receptacle...)
if err != nil {
tx.Rollback()
return nil, err
}
}
rows.Close()
[...]
}
func main() {
var myInt1 int
var myInt2 int
var myString string
All(&myInt1, &myInt2, &myString)
//all 3 variables are correctly set
}
Here, receptacle is variadic.
If my query returns two int and one string, instead of doing rows.Scan(&myInt1, &myInt2, &myString), I am using the function's arguments rows.Scan(args...).
This is perfectly working when one, and only one, a row is requested from the BD.
What I would like to do is to use the same process to store multiple rows :
func main() {
var myInts1 []int
var myInts2 []int
var myStrings []string
All(&myInts1, &myInts2, &myStrings)
//myInts1 == []int{firstRowInt1, secondRowInt1, ...}
//myInts2 == []int{firstRowInt2, secondRowInt2, ...}
//myStrings == []string{firstRowString, secondRowString, ...}
}
Is there a way to tell a function to use the index X of a variadic argument, something like this: rows.Scan(receptacle[0]...) ?
My guess (and tries) is no, but wanted to confirm this hypothesis

Value of optional type must be unwrapped to refer to member, BUT its for an implicitly unwrapped optional property

Why am I getting this? Its an implicitly unwrapped optional property. I don't think I should be getting this error. I tried cleaning my build folder and deleting derived data, and closing Xcode. Nothing worked.
var questionsWrap: QuestionsWrapper
func userMadeSelection(
_ responseId: Int,
_ myTheir: Question.Response.Selections.MyTheir,
_ choice: Question.Response.Selections.MyTheir.Choice
) {
guard let id = question.id else { return }
questionsWrap.saveSelection(
questionId: id,
responseID: responseId,
myTheir: myTheir,
choice: choice
) { success in
if !success {
AlertViewController<Any>.alertFailure(
message: "We made a mistake and we weren't able to save your selection."
)
}
}
singleQuestionDataSource.observableQuestion.value = question
print(#line, "userMadeSelectionImportance: \(responseId) \(myTheir) \(choice)")
if choice.changedBetweenPolarAndNeutral(
with: questionsWrap.question.theirInteractionStyle
) {
let presenter = Question.Importance.Presenter(question)
update(presenter?.importance)
questionCell?.importancePresenter = presenter
}
}
Method definition
func saveSelection(
questionId: Int,
responseID: Int,
myTheir: Question.Response.Selections.MyTheir,
choice: Question.Response.Selections.MyTheir.Choice,
context: Context,
successAction: SuccessAction? = nil
) {
guard let questionIndex = questions.index(of: questionId),
let responseIndex = questions[questionIndex].responses.index(of: responseID) else {
successAction?(false)
return
}
questions[questionIndex].responses[responseIndex].set(myTheir, choice, for: context)
let response = questions[questionIndex].responses[responseIndex]
URL.make(
my: response.choice(for: .my, UserDefaults.questionContext),
their: response.choice(for: .their, UserDefaults.questionContext),
forResponseID: responseID,
forQuestionID: questionId,
forContext: UserDefaults.questionContext
).get { jsonDict in
successAction?(jsonDict.success)
}
}
Unfortunately, I don't know what code to provide to recreate this issue atomically.
I am stepping outside of the norm and posting a screen shot to prove that the error is showing.
The usual reason for seeing this error message with an implicitly unwrapped Optional is that implicit unwrapping does not promulgate itself thru assignment. For example, this is legal:
var s : String!
print(s.count)
But this is not:
let s2 = s
print(s2.count) // value must be unwrapped
I figured it out, I changed the method signature for saveSelection to require another parameter, but I forgot to add a default value or add the argument in the call. I don't know why the compiler wasn't telling me that instead...

Modifying struct instance using call to name in function parameter

I am attempting to use Parse to call up some variables and put them into a struct that is already initialized. The calling of the variables is happening smoothly and the data is available, but the inputing of the class into the function is not happening.
'unit' is a struct that has the name, hp, attack, etc. variables contained within it.
Is it not possible to pass along an instance of a struct and modify it's values like this? It would save me a lot of copy-pasting code to do it this way.
Thanks for your help!
func fetchStats(name: String, inout nameOfClass: unit) {
var unitStatArray = []
let query = PFQuery(className: "UnitStats")
query.whereKey("name", equalTo: name)
query.findObjectsInBackgroundWithBlock{(objects:[PFObject]?, error: NSError?)->Void in
if (error == nil && objects != nil){ unitStatArray = objects! }
nameOfClass.name = "\(unitStatArray[0].objectForKey("name")!)"
print("class name is \(nameOfClass.name)")
print("cannon name is \(cannon.name)")
nameOfClass.hitPoints = unitStatArray[0].objectForKey("hitPoints") as! Double
nameOfClass.hitPointsMax = unitStatArray[0].objectForKey("hitPointsMax") as! Double
nameOfClass.attack = unitStatArray[0].objectForKey("attack") as! Double
nameOfClass.defense = unitStatArray[0].objectForKey("defense") as! Double
nameOfClass.rangedAttack = unitStatArray[0].objectForKey("rangedAttack") as! Double
nameOfClass.rangedDefense = unitStatArray[0].objectForKey("rangedDefense") as! Double
nameOfClass.cost = unitStatArray[0].objectForKey("cost") as! Int
}
}
fetchStats("3-inch Ordnance Rifle", nameOfClass: &cannon)
This is an attempt to explain what I had in mind when writing my comment above.
Because there's an asynchronous call to findObjectsInBackgroundWithBlock, the inout won't help you here. The idea is to add a callback fetched like this:
func fetchStats(name: String, var nameOfClass: unit, fetched: unit -> ()) {
// your code as above
query.findObjectsInBackgroundWithBlock {
// your code as above plus the following statement:
fetched(nameOfClass)
}
}
This can be called with
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
nameOfClass = newNameOfClass
}
(all of this code has not been tested)
The point is that you understand that your code is asynchronous (I know, I'm repeating myself). After you have called fetchStats you don't know when the callback (here: the assignment nameOfClass = newNameOfClass) will be executed. You cannot assume the assignment has been done after fetchStats has returned.
So whatever you need to do with the changed nameOfClass: the corresponding statements must go into the callback:
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
// do whatever you want with the received newNameOfClass
}
Hope this helps.

Calling function with optional type in Swift

Let's say I have the following:
var didConnectObserver: NSObjectProtocol?
didConnectObserver = NSNotificationCenter.defaultCenter().addObserverForName(
MyKey, object: nil, queue: nil, usingBlock: { (note) -> Void in
...
})
At some point I unregister:
NSNotificationCenter.defaultCenter().removeObserver(didConnectObserver)
This doesn't work, though, because didConnectObserver is an optional. Is there a more compact way to write this than:
if let obs = didConnectObserver {
NSNotificationCenter.defaultCenter().removeObserver(obs)
}
that still does the right thing if didConnectObserver is nil?
I'm still getting the hang of map with Optionals, but I believe this will work:
_ = didConnectObserver.map(NSNotificationCenter.defaultCenter().removeObserver)
If didConnectObserver is nil, the result of this is nil, otherwise it executes the function with didConnectObserver!. The _ = is necessary to suppress a warning Result of call to 'map' is unused.
Here's what autocomplete shows when you type didConnectObserver.map:
Here is another example of the same concept:
func add5(i: Int) {
print("add 5 called")
print(i + 5)
}
let a: Int? = 10
_ = a.map(add5)
If a is nil, then add5 is not called. If a is Optional(10), then add5 is called and 15 is printed.
It works just like:
if a != nil {
add5(a!)
}