はじめに
今回学習の中で、構造体について学ぶ機会があったのでまとめました
構造体とは?
いくつかのデータをまとめて一つの塊にしたもの
バラバラに管理するより、一つにグルーピングして管理、利用したほうがわかりわすいため
Ruby修学者ならモデルの作成でカラムを作ったと思いますが
- 構造体 = モデル
- 構造体内の各データ = カラム
と考えれば理解しやすいのでは無いのでしょうか
構造体のメリット
- シンプルで読みやすいコードを書くことができる
- 構造体は値型であるため、参照型のクラスよりも安全にデータを扱うことができる
- 構造体を使用することでビューの再利用性が高まる
- 同じ構造体を使用して異なるデータを表示することができるため、コードの重複を避けることができる
使い方
.swift
//人のデータを管理する構造体
struct Person {
//変数(定数でもOK)、構造体内のこれらをプロパティと呼ぶ
var firstName: String
var lastNmae: String
var age: Int
var email: String
//列挙型も入れることが出来る
enum Gender {
case male
case female
}
}
イニシャライザ
構造体は定義時は雛形であり、そのまま使用することはできない。
そこで構造体が使用可能になり、値が保存ができる状態にすることをインスタンス変数という。
そして、インスタンス生成のための初期化の手続きをイニシャライザという。
イニシャライザはinitで指定できる
.swift
struct Person {
var name: String
var age: Int
var email: String
// イニシャライザの定義
init(name: String, age: Int, email: String) {
self.nmae = name
self.age = age
self.email = email
}
// イニシャライザの定義(応用例)
init(firstNmae: String, lastName: String, age: Int, email: String) {
name = firstName + lastName
self.age = age
self.email = email
}
}
let person1 = Person(name: "山田", age: 30, email: "taro@example.com")
print(person1) //=> 山田、30、taro@example.com
let person2 = Person(firstName: "山田", lastName: "太郎", age: 30, email: "taro@example.com")
print(person2) //=> 山田太郎、30、taro@example.com
//実際のviewでの書き方
struct ContentView: View {
var body: some View {
HStack{
Text("Age: \(person2.age)") //=> Age: 30
Text(person2.name) //=> 山田太郎
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
}
イニシャライザの省略
インスタンス作成時にプロパティについて初期値を設定するならイニシャライザは省略できる
また、構造体内で初期値を設定しているプロパティは省略できる
.swift
struct Person {
var firstName: String
var lastNmae: String
var age: Int = 18 //ageには初期値を設定
var email: String
enum Gender {
case male
case female
}
}
//ageは30に変更
let person = Person(firstName: "太郎", lastNmae: "山田", age: 30, email: "taro@example.com", gender: .male)
//初期値があれば省略可能、この場合ageは18になる
let person = Person(firstName: "太郎", lastNmae: "山田", email: "taro@example.com", gender: .male)
クラスとの違いについて
継承: 構造体は継承できないが、クラスは継承できる
.swift
//クラスAnimalの作成
class Animal {
var name: String
init(name: String) {
self.name = name
}
func makeSound() -> String {
return "Unknown sound"
}
}
//クラスDogを作成しAnimalの設定を継承
class Dog: Animal {
override func makeSound() -> String {
return "Bark"
}
}
let animal = Animal(name: "Animal")
let dog = Dog(name: "Dog")
//class Animalの出力
print(animal.name) // "Animal"
print(animal.makeSound()) // "Unknown sound"
//class Dogを出力
print(dog.name) // "Dog"
//makeSoundを上書きしている
print(dog.makeSound()) // "Bark"
構造体ではこのような事ができない
値渡しと参照渡し: 構造体は値渡し、クラスは参照渡し
構造体は値渡しであるため、関数内での変更が元の値に影響しない
.swift
struct MyStruct {
var value: Int
}
//インスタンスnumberを生成し、valueを10とする
var number = MyStruct(value: 10)
//valueを20へ変更する関数modifyStructを作成する
func modifyStruct(struct: MyStruct) {
var newNumber = number
newNumber.value = 20
print(newNumber.value) // 出力結果: 20
}
//インスタンスnumberのvalueを出力する
print(number.value) // 出力結果: 10
//関数modifyStructを実行する
modifyStruct(struct: number)
//インスタンスnumberのvalueを出力する
print(number.value) // 出力結果: 10
クラスは参照渡しであるため、関数内での変更が元の値に影響する
.swift
class MyClass {
var value: Int
init(value: Int) {
self.value = value
}
}
//インスタンスnumberを生成し、valueを10とする
var number = MyClass(value: 10)
//valueを20へ変更する関数modifyClassを作成する
func modifyClass(class: MyClass) {
var newNumber = number
newNumber.value = 20
print(newNumber.value) // 出力結果: 20
}
//インスタンスnumberのvalueを出力する
print(number.value) // 出力結果: 10
//関数modifyClassを実行する
modifyClass(class: number)
//インスタンスnumberのvalueを出力する
print(number.value) // 出力結果: 20
参照
クラスとの違いについて