Aller au contenu


Photo

Accès aux membres d'une struct par nom et par indice

Swift struct propriétés

  • Please log in to reply
42 réponses à ce sujet

#1 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 01 février 2017 - 14:47

Bonjour à tous,

J'ai une question pour ceux qui maîtrisent Swift mieux que moi.
J'ai un vecteur à trois composantes, x, y et z, et j'aimerais y accéder soit par le nom des composantes (vecteur.y), soit par un indice (vecteur[1]).

J'ai cette manière de faire, en auriez-vous une meilleure à me proposer ? En l'état, ce qui me gène est la duplication de la donnée. Mais ce qui me plaît est que l'accès est aussi rapide dans les deux cas.
 
struct Vec3 {
    let x: Float
    let y: Float
    let z: Float
    let components: [Float]

    init(_ x: Float, _ y:Float, _ z:Float) {
        self.x = x
        self.y = y
        self.z = z
        self.components = [x, y, z]
    }
}

RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#2 Pyroh

Pyroh

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 478 messages

Posté 01 février 2017 - 15:45

Tu rajoutes le subscript : 

struct Vec3 {
    let x: Float
    let y: Float
    let z: Float
    
    subscript(index: Int) -> Float {
        get {
            switch index {
            case 0 : return self.x
            case 1 : return self.y
            case 2 : return self.z
            default: assertionFailure("Valid indexes are [0, 1, 2]. \(index) is out of bounds")
            }
            return Float()
        }
    }
}

let v = Vec3(x: 1, y: 2, z: 3)
v[0] // returns 1
v[1] // returns 2
v[2] // returns 3
v[4] // fatal error: Valid indexes are [0, 1, 2]. 4 is out of bounds

Tout simplement  :bravo!:


  • Draken, Larme et colas_ aiment ceci

#3 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 599 messages
  • LocationParis

Posté 01 février 2017 - 15:47

Moi j'ai ça :

struct Vec3 {
    let components: [Float]
    
    var x:Float {
        get { return self.components[0] }
    }
    
    var y:Float {
        get { return self.components[1] }
    }
    
    var z:Float {
        get { return self.components[2] }
    }
    
    init(_ x: Float, _ y: Float, _ z:Float) {
        self.components = [x, y, z]
    }
}


Utilisation :

let v = Vec3(1.0, 2.0, -1.0)
let x1 = v.x
print ("x1 : ", x1)
let x2 = v.components[0]
print ("x2 : ", x2)

 

x1 :  1.0

x2 :  1.0

 

Garçon, servez-moi un Covfefe avec du lait de soja, sans OGM ..

Et faites régler la climatisation, il fait bien chaud, ici !

 

 

Éternel Novice !  :baby:

Tueur de poneys !  :(

 

Faire simple .. c'est compliqué !

Faire compliqué .. c'est simple !

 

Un MOOC (cours en ligne - dont je ne suis pas l'auteur) gratuit sur la programmation en Obj-C et en Swift 3, démarrant le 14 Mars 2017 :

https://www.edx.org/...onnex-progios1x

 

Des dizaines d'heures de tutoriels vidéo en français (je ne suis pas l'auteur) pour apprendre à développer en Obj-C et Swift : http://pagesperso-sy...don/5I452-2014/

 

 


#4 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 01 février 2017 - 16:08

Merci tous les deux pour vos réponses.
J'avoue avoir une préférence pour la version de Pyroh, la notation en subscript (vec[0]) étant moins lourde.
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#5 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 599 messages
  • LocationParis

Posté 01 février 2017 - 16:17

J'avoue avoir une préférence pour la version de Pyroh, la notation en subscript (vec[0]) étant moins lourde.

Oui, j'ai pensé la même chose en lisant sa solution. Son approche est plus esthétique que la mienne. 


Garçon, servez-moi un Covfefe avec du lait de soja, sans OGM ..

Et faites régler la climatisation, il fait bien chaud, ici !

 

 

Éternel Novice !  :baby:

Tueur de poneys !  :(

 

Faire simple .. c'est compliqué !

Faire compliqué .. c'est simple !

 

Un MOOC (cours en ligne - dont je ne suis pas l'auteur) gratuit sur la programmation en Obj-C et en Swift 3, démarrant le 14 Mars 2017 :

https://www.edx.org/...onnex-progios1x

 

Des dizaines d'heures de tutoriels vidéo en français (je ne suis pas l'auteur) pour apprendre à développer en Obj-C et Swift : http://pagesperso-sy...don/5I452-2014/

 

 


#6 Pyroh

Pyroh

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 478 messages

Posté 02 février 2017 - 10:23

Y'a juste un truc qui me gène dans ma solution c'est le :

return Float()

à la fin du subscript. Il serait bon soit d'avoir une solution un peu plus propre ou une possibilité dans Swift de pouvoir marquer une fonction comme étend faillible sans forcément utiliser les erreur avec un throws qui impliquerai plus de code chiant à l'usage. 

 

En fait j'aimerai savoir si quelqu'un à une solution avant de proposer quelque chose dans Swift Evolution.

 

Je n'ai encore eu le temps de regarder si c'était dedans.



#7 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 02 février 2017 - 10:36

Y'a juste un truc qui me gène dans ma solution c'est le :

return Float()
à la fin du subscript. Il serait bon soit d'avoir une solution un peu plus propre ou une possibilité dans Swift de pouvoir marquer une fonction comme étend faillible sans forcément utiliser les erreur avec un throws qui impliquerai plus de code chiant à l'usage.


Ça ne me pose pas de problème, sachant que c'est un cas qui n'est pas sensé arriver sauf si je fais une erreur.

À noter que je n'ai pas eu à écrire get { } dans mon implémentation.
  • colas_ aime ceci
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#8 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 02 février 2017 - 11:11

Je suis bien consicient que la demande imposait de pouvoir accéder aux composants via un index de 0 à 2.

struct Vec3 {
    let x: Float
    let y: Float
    let z: Float
    let components: [Float]

    init(_ x: Float, _ y:Float, _ z:Float) {
        self.x = x
        self.y = y
        self.z = z
        self.components = [x, y, z]
    }
}

Dans le cas de Pyroh on ne peut pas faire :

let v = Vec3(1,2,3)
v.components

Si il me fallait absolument cette propriété pour X raison. Le mieux serait quoi ? De passer par une propriété calculée ?

var components: [Float] {
   return [x,y,z]
}

Twitter : @jrmguimberteau


#9 Pyroh

Pyroh

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 478 messages

Posté 02 février 2017 - 14:23

Voilà une solution qui conviendrait normalement à tout le monde :

struct Vec3 {
    let x: Float
    let y: Float
    let z: Float
    var components: [Float] {
        get { return [x, y, z] }
    }
    
    subscript(index: Int) -> Float {
        return components[index]
    }
}

let v = Vec3(x: 1, y: 2, z: 3)
v[0] // returns 1
v[1] // returns 2
v[2] // returns 3
v[4] // fatal error: Index out of range

components est certes calculée mais c'est pas super grave vu qu'on a que 3 occurrences.

Après c'est surtout moi qui ne veut pas mettre d'init quand c'est pas vraiment nécessaire.



#10 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 02 février 2017 - 14:39

components est certes calculée mais c'est pas super grave vu qu'on a que 3 occurrences.

Après c'est surtout moi qui ne veut pas mettre d'init quand c'est pas vraiment nécessaire.

 

Petite question au passage. Dans ce cas là, components serait calculé à l'instanciation de l'objet ? Si oui (en admettant que Vec3 soit une classe) que se passerait il pour ce champ si je fais :

let v = Vec3(1.0, 2.0, -1.0)
v.x = 2.3
v.y = v.x
v.z = v.x * 2.0
let c = v.components

components est recalculé lorsque l'un des trois champs change de valeur ?


Twitter : @jrmguimberteau


#11 colas_

colas_

    Broyeur de fèves

  • Membre
  • PipPipPipPipPipPip
  • 1 431 messages

Posté 02 février 2017 - 14:56

Je dirais que components est calculé à chaque appel.


small-logo.png

Mathématiques pour classes prépa et enseignement supérieur sur iPad et iPhone

www.improov.fr > < Improov sur facebook >


#12 Pyroh

Pyroh

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 478 messages

Posté 02 février 2017 - 15:50

Je dirai surtout qu'avec des let partout le compilo s'allumerai comme un sapin de Noël... 

Sinon oui components est calculé à chaque appel.



#13 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 599 messages
  • LocationParis

Posté 02 février 2017 - 15:59

Je dirais que components est calculé à chaque appel.

Je suis du même avis. D'ailleurs c'est facile à vérifier, avec un point d'arrêt ou un print().

 

EDIT : Preuve par l'expérience

 

La nouvelle version Vec3, avec l'init, et un message à chaque régénération du tableau :

struct Vec3 {
    let x: Float
    let y: Float
    let z: Float
    var components: [Float] {
        get {
            print ("recalcul du tableau [x,y,z]")
            return [x, y, z] }
    }
    
    subscript(index: Int) -> Float {
        return components[index]
    }
    
    init(_ x: Float, _ y: Float, _ z:Float) {
        self.x = x
        self.y = y
        self.z = z
    }
}

Mise en oeuvre :

let v = Vec3(1.0, 2.0, -1.0)
        
let x1 = v.x
print ("x1 : ", x1)
        
let x2 = v[0]
print ("x2 : ", x2)
        
let y2 = v[1]
print ("y2 : ", y2)
        
let z2 = v[2]
print ("z2 : ", z2)

Résultat :

 

 

x1 :  1.0

recalcul du tableau [x,y,z]

x2 :  1.0

recalcul du tableau [x,y,z]

y2 :  2.0

recalcul du tableau [x,y,z]

z2 :  -1.0

 
Je doute que Ceroce soit heureux de la perte de ressources (processeur et mémoire) occasionné par la reconstruction du tableau, à chaque lecture d'une seule valeur. Ce n'est pas gênant pour un appel de temps en temps, mais lui bosse sur des moteurs de rendu 3D en ray-tracing. Il a besoin d'accéder des MILLIONS de fois par seconde à des coordonnées x,y,z. Un micro-ralentissement répété des MILLIONS de fois à la seconde, c'est .. problématique !

Garçon, servez-moi un Covfefe avec du lait de soja, sans OGM ..

Et faites régler la climatisation, il fait bien chaud, ici !

 

 

Éternel Novice !  :baby:

Tueur de poneys !  :(

 

Faire simple .. c'est compliqué !

Faire compliqué .. c'est simple !

 

Un MOOC (cours en ligne - dont je ne suis pas l'auteur) gratuit sur la programmation en Obj-C et en Swift 3, démarrant le 14 Mars 2017 :

https://www.edx.org/...onnex-progios1x

 

Des dizaines d'heures de tutoriels vidéo en français (je ne suis pas l'auteur) pour apprendre à développer en Obj-C et Swift : http://pagesperso-sy...don/5I452-2014/

 

 


#14 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 02 février 2017 - 16:09

Je dirai surtout qu'avec des let partout le compilo s'allumerai comme un sapin de Noël... 

 

Bien vu ! :prie!:

Nous supposerons que nous avons des var... ;)
 

Je dirais que components est calculé à chaque appel.

 

J'aurais dit la même chose dans la mesure où le mot clé lazy (lazy var x: Int = {...}) n'aurait pas grand intérêt... :huh:


Twitter : @jrmguimberteau


#15 colas_

colas_

    Broyeur de fèves

  • Membre
  • PipPipPipPipPipPip
  • 1 431 messages

Posté 02 février 2017 - 17:09

@Jérémy : qu'est-ce que ça change de mettre lazy ? C'est pour des let ?


small-logo.png

Mathématiques pour classes prépa et enseignement supérieur sur iPad et iPhone

www.improov.fr > < Improov sur facebook >


#16 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 02 février 2017 - 17:19

Non non non

var x: Int {...}
lazy var y: Int {...}

x sera calculé lorsque l'objet sera instancié alors que y sera calculé lors de son premier appel.

 

Exemple (le code est complètement débile mais c'est pour illustrer ce que je viens de dire) :

class Point {
   var x: Int
   var y: Int

   var adding: Int = {
      return x + y
   }

   lazy var multiplaying: Int = {
      return x*y
   }

   init(_ x: Int, _ y: Int) {
      self.x = x
      self.y = y
   }
}

let point: Point = Point(3,2)
// Ici adding aura été calculé alors que multiplaying sera à nil
// tant que tu ne l'auras pas appelé une première fois

Twitter : @jrmguimberteau


#17 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 02 février 2017 - 17:36

Jérémy. Je ne sais pas ce que tu crois que tu fasses  ::)

 

On ne ni add, ni multiply, les coordonnées d'une pointe. En plus, là, il vaut mieux d'utiliser une struct qu'une classe

 

À part du fait qu'il y a déjà les structs Point, Size, etc en Swift, voici un exemple de comment on peut faire telle struct :

struct Point
{
  var x: Int
  
  var y: Int
}

func +(lhs: Point, rhs: Point) -> Point
{
  return Point(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}

func *(lhs: Point, rhs: Int) -> Point
{
  return Point(x: lhs.x * rhs, y: lhs.y * rhs)
}

// test
  {
    let p1 = Point(x: 5, y: 5)
    
    print(p1)
    
    let p2 = Point(x: 2, y: 3)
    
    print(p2)
    
    let p3 = p1 + p2
    
    print(p3)
    
    let p4 = p3 * 4
    
    print(p4)
  }


#18 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 02 février 2017 - 17:45

Ou, pour jouer plus avec le vecteur de Céroce :

struct Vector
{
  var x: Float
  
  var y: Float
  
  var z: Float
  
  subscript(index: Int) -> Float?
  {
    get
    {
      switch index
      {
        case 0 : return self.x
        
        case 1 : return self.y
        
        case 2 : return self.z
        
        default: return nil
      }
    }
  }
  
  subscript(index: String) -> Float?
  {
    get
    {
      switch index
      {
        case "x" : return self.x
        
        case "y" : return self.y
        
        case "z" : return self.z
        
        default: return nil
      }
    }
  }
}

func +(lhs: Vector, rhs: Vector) -> Vector
{
  return Vector(x: lhs.x + rhs.x, y: lhs.y + rhs.y, z: lhs.z + rhs.z)
}

func *(lhs: Vector, rhs: Float) -> Vector
{
  return Vector(x: lhs.x * rhs, y: lhs.y * rhs, z: lhs.z * rhs)
}

8--)



#19 colas_

colas_

    Broyeur de fèves

  • Membre
  • PipPipPipPipPipPip
  • 1 431 messages

Posté 02 février 2017 - 17:50

@Jérémy : merci pour tes explications :-)

@Joana : merci aussi ;-)


small-logo.png

Mathématiques pour classes prépa et enseignement supérieur sur iPad et iPhone

www.improov.fr > < Improov sur facebook >


#20 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 02 février 2017 - 18:07

Jérémy. Je ne sais pas ce que tu crois que tu fasses  ::)

 

On ne ni add, ni multiply, les coordonnées d'une pointe. En plus, là, il vaut mieux d'utiliser une struct qu'une classe

 

C'est pour ça que j'ai dit :

 

Exemple (le code est complètement débile mais c'est pour illustrer ce que je viens de dire) :

 

::)  ::)  ::) (je suis pardonné maintenant ?  :P )

 

@Jérémy : merci pour tes explications :-)

@Joana : merci aussi ;-)

 

De rien  :bravo!:


Twitter : @jrmguimberteau






Also tagged with one or more of these keywords: Swift, struct, propriétés

0 utilisateur(s) li(sen)t ce sujet

0 membre(s), 0 invité(s), 0 utilisateur(s) anonyme(s)