In Swift, it is possible to convert certain literals to other types automatically:
let _: Double = 1 // Int literal to Double variable
However, when it comes to structs, compiler refuses to perform a similar conversion:
struct User {
var id: Int
var name: String
}
let _: User = (id: 778, name: "Pete") // error: cannot convert value of type '(id: Int, name: String)' to specified type 'User'
Defining an initialiser with respective fields does not help either.
Is there a way to omit the explicit initialiser of a structure, when the type is clear from the context?
2. make_tuple () :- make_tuple () is used to assign tuple with values. The values passed should be in order with the values declared in tuple. In the above code, get () modifies the 1st nd 3rd value of tuple. 3. tuple_size :- It returns the number of elements present in the tuple.
Tuple types are value types; tuple elements are public fields. That makes tuples mutable value types. The tuples feature requires the System.ValueTuple type and related generic types (for example, System.ValueTuple<T1,T2> ), which are available in .NET Core and .NET Framework 4.7 and later.
1. get () :- get () is used to access the tuple values and modify them, it accepts the index and tuple name as arguments to access a particular tuple element. 2. make_tuple () :- make_tuple () is used to assign tuple with values. The values passed should be in order with the values declared in tuple.
NB! To use tuple literals add NuGet package reference to System.ValueTuple package. We also win on calling code side as we get rid of those additional variables that made code more readable. Our code is now more readable and it covers the called method and calling code.
In Swift, the only literals that can be used to instantiate a type are Int
, Double
, String
, Bool
, and Array
's and Dictionary
's. Tuples are not allowed.
Swift aims to be a strongly typed langage, so you should use:
let user = User(id: 778, name: "Pete")
Which is both explicit and short, and not more verbose than what you are looking for.
However, you can conform any of your type to any ExpressibleBy<LiteralType>Literal
. Here is a fun way to achieve a similar behavior to tuple initialization:
struct User {
var id: Int
var name: String
}
extension Person: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (String, Any)...) {
let elements = Dictionary(uniqueKeysWithValues: elements)
self.id = elements["id"]! as! Int
self.name = elements["name"]! as! String
}
}
let user: User = ["id": 778, "name": "Pete"]
Which is both unsafe and inefficient.
A safer but less convenient way is using a static factory method:
extension User {
static func t(_ tuple: (Int, String)) -> User {
User(id: tuple.0, name: tuple.1)
}
}
let user: User = .t((id: 778, name: "Pete"))
Another interesting thing is that in certain contexts, the compiler will allow the use of a tuple which exactly matches an initializer signature to be used, for instance when using map
:
let persons = [(id: 778, name: "Pete")]
let users = persons.map(User.init)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With