44 votes

Swift Initialize Struct avec des propriétés stockées facultatives

Je suis un débutant en Swift et j'essaie de me faire une idée de l'utilisation des structures avec des propriétés facultatives. J'ai fait pas mal de recherches et j'ai obtenu quelque chose qui fonctionne mais qui semble incroyablement inefficace. Je me demandais donc s'il existait un moyen meilleur/plus facile à gérer pour atteindre mon objectif.

J'aimerais utiliser des Structs pour représenter une entreprise, mais je n'ai aucune idée à l'avance de la combinaison de propriétés qu'une entreprise spécifique est susceptible d'avoir. Cela semble signifier que je dois créer un init() pour chaque combinaison possible de paramètres.

Voici un exemple simplifié (j'ai beaucoup plus de propriétés) :

import Foundation

struct Business {
    let name : String
    var web : String?
    var address: String?

    // just the business name
    init(busName: String) {
        self.name = busName
    }

    // business name + website
    init(busName: String, website: String) {
        self.name = busName
        self.web = website
    }

    // business name + address
    init(busName: String, address: String) {
        self.name = busName
        self.address = address
    }

    // business name + website + address
    init(busName: String, website: String, address: String) {
        self.name = busName
        self.web = website
        self.address = address
    }
}

Je peux alors initialiser la classe comme ceci :

Business(busName: "Dave's Cafe", website: "http://www.davescafe.com")

Business(busName: "Sarah's Brewhouse", address: "41 Acacia Ave, Smalltown")

N'y a-t-il pas moyen de créer une sorte de init() où les paramètres sont facultatifs ? Si vous pouviez m'indiquer des termes ou des concepts à rechercher, ce serait formidable.

73voto

dasdom Points 6905

Utiliser les valeurs par défaut :

init(busName: String, website: String? = nil, address: String? = nil) {
    self.name = busName
    self.web = website
    self.address = address
}

Ensuite, vous pouvez appeler l'init comme ceci :

_ = Business(busName: "Foo")
_ = Business(busName: "Foo", website: "www.foo.bar")
_ = Business(busName: "Foo", address: "bar")
_ = Business(busName: "Foo", website: "www.foo.bar", address: "bar")

1 votes

Ceux-ci devraient être String? et non String .

0 votes

Merci @dasdom J'ai essayé d'utiliser le ? après le type (par exemple ... website: String? ... car je pensais que l'utilisation de cette syntaxe mettait automatiquement la valeur à zéro. Cela n'a pas fonctionné et je n'ai pas essayé de mettre explicitement la valeur à nil. Je vais l'essayer maintenant.

0 votes

Oui, String o String? est juste un type ; il n'a pas grand chose à voir avec une valeur par défaut (tant que nous parlons de paramètres de fonction). Vous auriez également pu avoir une valeur par défaut pour un paramètre String, comme par exemple init(busName: String = "") bien que je pense que les options sont la bonne voie à suivre pour cela.

10voto

dasblinkenlight Points 264350

Une approche que vous pouvez emprunter à d'autres langages de programmation opérationnelle est le modèle de construction de paramètres. Commencez par une méthode statique qui renvoie un constructeur, puis ajoutez des méthodes pour les paramètres individuels, et enfin appelez build() :

let bakery = Business
    .withName("Black Forest")
    .andWebSite("www.blackforest.com")
    .andAddress("1 Main St, Springfield, IA 98765")
    .build()

Voici une implémentation squelettique qui permet ce type d'API :

class Business {
    // Users never call this init, it's for the builder to use
    init(name: String, webSite: String?, address: String?) {
        ...
    }
    // Here is the method the users call:
    static func withName(name: String) {
        return BusinessBuilder(name)
    }
    // This class collects parameters before calling init
    class BusinessBuilder {
        var name : String
        var webSite : String?
        var address: String?
        func andAddress(address: String) -> BusinessBuilder {
            self.address = address
            return self
        }
        func andWebSite(webSite: String) -> BusinessBuilder {
            self.webSite = webSite
            return self
        }
        func build() -> Business {
            return Business(name, webSite, address)
        }
        init(name: String) {
            self.name = name
        }
    }
}

Cela vous permet de passer autant de paramètres d'initialisation que vous le souhaitez, dans l'ordre qui vous convient dans une situation donnée.

La principale utilisation de cette approche est lorsque vous ne savez pas quels paramètres vous allez obtenir, par exemple, lorsqu'ils proviennent d'un XML ou d'une base de données. Vous pouvez appeler andXyz dans une boucle, et ensuite appeler build() lorsque vous n'avez pas d'autres attributs à définir.

0 votes

Builder semble inutile pour l'exemple simple du PO, mais il pourrait être utile si le PO a l'intention de s'étendre à plus de champs.

13 votes

AMomchilov On dit souvent que les modèles de conception sont des solutions de rechange pour les fonctionnalités manquantes du langage de programmation. Le patron Builder a été introduit en Java principalement pour compenser l'absence de la fonctionnalité de paramètre nommé dans le langage. Swift, en revanche, résout ce problème de manière native, de sorte que la principale raison d'utiliser le builder en Swift est de pouvoir passer les paramètres de l'initialisateur un par un.

0 votes

Java n'avait pas non plus de paramètres par défaut, ce qui peut vous obliger à utiliser le modèle de construction pour une classe ne comportant que quelques paramètres.

0voto

Jeffrey Points 1

J'espère que cela pourra vous aider

 struct Business {
    let name : String
    var web : String?
    var address: String?

// you also need use question mark in init progress
init(name: String, web: String?, address: String?) {
    self.name = name
    self.web = web
    self.address = address
    }
}

Une fois que vous avez créé un objet, vous pouvez utiliser nil sur votre valeur optionnelle. Par exemple :

var newBusiness = Business(name: "AWS", web: nil, address: nil)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X