Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a structure auto-convertible from a tuple literal?

Tags:

swift

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?

like image 360
Zomagk Avatar asked Aug 28 '16 20:08

Zomagk


People also ask

What is the difference between make_tuple () and tuple_size?

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.

What is the difference between tuple and valuetuple?

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.

How to use make_tuple () in Python?

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.

How to use tuple literals with NuGet?

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.


1 Answers

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)
like image 89
Louis Lac Avatar answered Jan 02 '23 05:01

Louis Lac