Does declaring a variable as optional incurs any additional cost in swift? - swift2

As per my boss, if I am initialising a variable in init, I should not declare it as optional and he thinks book on swift says that.
Now I haven't came across the same statement anywhere hence wondering is he correct or not.
OverView:
As I come from an Object oriented Objective C programming background, it is my hobby to declare the variables to their initial values as soon as I declare it (most of the Stanford university videos on Objective C said the same thing) Now objective C used to allow a nil value to the variables and if I want to assign the same nil value as initial value to some variable in swift I need to declare it as optional, I know that if I declare a variable and won't initialise it in init I'll get error from compiler,
struct TestStruct {
var name : String? = nil
var age : Int
init(){
name = "Sandeep"
age = 26
}
func printInfo(){
print(self.name! + "\(self.age)")
}
}
In the above code I have name declared as optional and set nil as default value where as age is defined as Int and initialised to proper value in init.
Question
Knowing that both work,
1.Is it wrong if I declare a variable as optional and then use ! or ? to access it even though I initialise it in init??
2.Is it true that swift specifies that I should not use ? or ! for the variables ? If yes is there any added computational cost to it ?
I know it is not a complicated question, I just wanna know what I am doing is anyway wrong?
Thanks in advance.

Assuming you don't want to reset your struct's name to nil ever, initialize the variables with the values you want them to have. It simplifies the code and expresses the idea of default values.
struct TestStruct {
var name = "Sandeep"
var age = 26
func printInfo(){
print(self.name + "\(self.age)")
}
}

Yes, your boss is correct but it depends on the requirements. If you are for sure that you would be having a name and age then you can avoid optionals for these two. If you are not sure about the values then you should use the optionals like for address or phone number etc. And also it is best practice to initialize with the parameters in the struct like below:
struct TestStruct {
var name : String?
var age : Int
init(name: String?, age: Int){
self.name = name
self.age = age
}
func printInfo(){
//Since your name property is an optional, you should check for a nil before using it.
print("Name:", (self.name ?? "") + "\nAge: \(self.age)")
}
}
let myStruct = TestStruct(name: "Sandeep", age: 26)
myStruct.printInfo()
//output
Name: Sandeep
Age: 26
let myStruct2 = TestStruct(name: nil, age: 18)
myStruct2.printInfo()
//output
Name: No Name provided
Age: 18

Related

How to get a struct tag without having to instantiate the struct

type User struct{
Name string `json:"name"`
}
func main() {
t := reflect.TypeOf(User{})
}
It is possible to capture the tag's values ​​without instantiating it. For example capturing the value of the tag "json" without having to instantiate the User structure.
Creating a value is not a performance issue in almost all scenarios, but you can avoid creating a value by using a nil pointer value.
t := reflect.TypeOf((*User)(nil)).Elem() // Elem "dereferences" the pointer type.
The reason to use the pointer pattern shown here is that the one syntax works with every type. In particular, it handles interface types:
type I interface{}
// Naive developers might expect the following
// to return the type for I, but it actually
// returns nil.
t := reflect.TypeOf(I(nil))
// The pointer pattern returns the type for I.
t = reflect.TypeOf((*I)(nil)).Elem()
The pointer syntax is the same for all types independent of how the zero value is written for the type:
t = reflect.TypeOf(User{})
t = reflect.TypeOf(uint(0))
t = reflect.TypeOf(myString(""))
Use t = reflect.TypeOf((*T)(nil)).Elem() where T is any type:
t = reflect.TypeOf((*User)(nil)).Elem()
t = reflect.TypeOf((*uint)(nil)).Elem()
t = reflect.TypeOf((*myString)(nil)).Elem()

Converting bool to *bool in go

With the following code:
var example *bool
example = true
log.Print(example)
I have the following error cannot convert true (untyped bool constant) to *bool
I manage to solve it declaring a new variable truevalue:
var example *bool
truevalue := true
example = &truevalue
log.Print(example)
But I imagine there is a better way to do it, without declaring any new variables.
A pointer has to point to something, which means you have to either assign it to the address of another variable (as in your second example), or initialize it with new() and then assign by dereference. Personally I'd recommend the former, as new is not widely used in Go. But, for demonstration:
example := new(bool)
*example = true
https://play.golang.org/p/0VO5jNPMutQ

Why must I pass type to make function when variable is already declared?

I want use anonymous struct to do something.
var users []struct{
Name string `json:"name,omitempty"`
Age int
}
and I have to write the type again to set value
users = make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
if I insist using anonymous struct, is there any way to make it more decent?
(if no, I wonder why golang design make function like this...)
Anonymous structs are handy for one-time use.
If you are using it more than once, then define a named struct type.
If you only use it within a single function, you can define the type within the scope of that particular function, so it's obvious that it cannot be used elsewhere:
func myfunc() {
type MyType struct {
Name string
}
m := MyType{Name: "Hello, World!"} // this type can only be used within this func
fmt.Println(m)
}
if I insist using anonymous struct, is there any way to make it more decent?
Yes, there is. Use :=:
users := make([]struct{
Name string `json:"name,omitempty"`
Age int
}, 0, 10)
Of course, this only works if you're calling make right after you're defining the variable. If these bits are separated by other code, this trick won't work for you.
But don't be afraid to name your types. That's generally a better approach anyway (with or without :=).

How to assign field name of struct from variable

I am new to golang and migrating from php to golang.
I am trying to do something like below stuff, where I want field name age to get assigned from variable test. Is this possible in golang?
In php, we have provision like $$test, looking something similar in golang as well.
package main
import "fmt"
// This `person` struct type has `name` and `age` fields.
type person struct {
name string
age int
}
func main() {
var test = "age"
fmt.Println(person{name: "Alice",test: 30})
}
This is just sample code replicating my use case.
You have three options, in rough order of preference:
1) An if/switch statement:
var p = &person{}
if key == "age" {
p.age = value
}
2) Use a map instead of a struct:
var p = map[string]interface{}
p[key] = value
3) Use reflection. See this question for details, but generally you should avoid reflection. It's slow, and non-idiomatic, and it only works with exported fields (your example uses un-exported fields, so as written, is not a candidate for reflection anyway).

Is there a shortcut for assigning a variable to a pointer without creating the variable in a separate line first?

If I have a struct like this:
type Message struct {
Id int64
Message string
ReplyTo *int64
}
And then if I did create an instance of this struct like this:
var m Message
m.Id = 1
m.Message = "foo bar yo"
var replyTo = int64(64)
m.ReplyTo = &replyTo
Then it would work.
But I was wondering if there was a shortcut for the last step?
I tried doing something like:
m.ReplyTo = &int64{64}
But it did not work.
I don't think you can because the value is a primitive and attempting to do it in one shot like the below would be a syntax error. Its attempting to get an address of a value so it wouldn't be possible. At least I am not aware of a way where its possible.
someInt := &int64(10) // would not compile
The other alternative you have is to write a function to return a pointer to the primitive like the following:
func NewIntPointer(value int) *int {
return &value
}
A tricky way to get int pointer without create new variable.
someIntPtr := &[]int64{10}[0]

Resources