#author("2016-07-01T07:35:17+00:00","default:nitta","nitta")
#author("2016-07-01T07:35:42+00:00","default:nitta","nitta")
[[Swift]]

*Swift/構造体 [#da7349de]

 struct 型名 {
   [変数/英数定義]
   [イニシャライザ定義]
   [メソッド定義]
   [その他の定義]
 }

struct内の変数はプロパティ(property)と呼ばれる。
 struct Date {
   var year: Int
   var month: Int
   var day: Int
 }

**構造体の初期値 [#s3bf720e]
初期化に使う手続きがイニシャライザ (initializer) である。
構造体の定義には、各プロパティの初期値を記述しておくことができる(default initializer)。
 struct Date {
   var year:Int = 2016  // 型を明記した場合
   var month = 7        // 型を初期値から推測させた場合
   var day = 28
 }
 var d = Date()
 print(d.day)    // 28 と表示される

**全項目イニシャライザ [#ta10d594]
個々のプロパティの値を指定してインスタンスを生成することができる(memberwise initializer)。
 var a = Date(year:2016, month:5, day: 13)
構造体は値型であり、代入はコピーによって行われる。
定数に代入した構造体の各プロパティは値を変更できない。
 let b = Date(year: 2016, month: 5, day: 13)
 b.year = 2017   // エラー

**構造体の定数プロパティ [#b07d8bc0]
構造体のプロパティとして定数を宣言することができる。
定数の値は指定できない。

 struct Time {
   let in24h: Bool = false     // 定数のプロパティ
   var hour = 0, min = 0       // 変数のプロパティ
 }
 var t1 = Time()   // 0:00 (12時間制)
 var t2 = Time(hour: 8, min: 50)     // 8:50 (12時間制)
 var t3 = Time(in24h:true, hour:7, min:0)   // 定数の値を与えようとするとエラーとなる。

初期値が与えられていない定数プロパティがある構造体は、初期値を設定しなけれえばならない。
初期値が与えられていない定数プロパティがある構造体は、初期値を設定しなければならない。
 struct Time {
   let in24h: Bool   // 初期値が指定されていない定数
   var hour = 0, min = 0
 }
 var t4 = Time(in24h:true, hour:7, min:0)   // 7:00 (24時間制)

**イニシャライザの定義 [#i3f0d7e3]
イニシャライザは init という名前で定義する。
init以外の名前(たとえば initWithData: )を指定することはできない。

イニシャライザの中では、その構造体のプロパティに自由にアクセスできる。
定数プロパティの初期化もこの中で行う。

イニシャライザ内で構造体のメソッドを使うことができるのは、すべてのプロパティの
初期設定が済んでから。したがって、メソッドを使ってプロパティの初期値を決めることはできない。

 struct Date {
   var year, month, day:Int
   init() {
     year = 2016; month = 5; day = 13   // self.year = 2016 のように書くこともできる
   }
 }
 var m = Date()
 print(m.year)    // 2016と表示される

**複数個のイニシャライザを定義する [#y109195b]
関数の定義とは異なり、イニシャライザの定義では第1引数として記述したキーワードも
外部引数名として使われる。

 struct Time {
   let in24h: Bool           // 初期値のない定数
   var hour = 0, min = 0
   init(hour:Int, min:Int) {
     in24h = false           // 定数の初期化
     self.hour = hour
     self.min = min
   }
   init(hourIn24 h:Int) {
     in24h = true            // 定数の初期化
     hour = h
   }
   init(_ hour:Int) {
     self.init(hourIn24: hour)   // 上のイニシャライザを使う
     // in24h = true            /* 定数の初期化が終わっているので、これはエラーになる */
   }
 }
 var a = Time(hour:10, min:30)    // 12時制 10:30
 var b = Time(hourIn24:15)        // 24時制 15:00
 var c = Time(1)                  // 24時制 1:00
 var d = Time()                   // エラー
 var e = Time(in24h:True, hour:13, min: 30)  // エラー

init を定義すると、default initializer や memberwise initializer は使えなくなる。
必要ならば、それと同じ呼び出し形式を持つinitを定義する。

**関数とイニシャライザ表記のまとめ [#ye1506a3]

|項目|イニシャライザ|関数/メソッド|
|手続き名|init|自由|
|返り値|記述しない|自由|
|外部引数名|全ての内部引数名が外部引数名になる|第1引数以外の内部引数名が外部引数名になる|
|外部引数名を使わない|_を指定する|_を指定する。第1引数への指定は冗長|

以下に関しては、どちらも指定可能である。
-引数に対するvarまたはletの指定
-inoutの指定 (ただしvar, letとの併用は不可)
-default値の指定 (ただしinoutとの併用は不可)
-可変長引数 (ただしvar, let, inoutとの併用は不可)
-定義のオーバーロード

**他の構造体を含む構造体 [#w1af1733]
 struct DateWithTime {
   var date = Date()
   var time = Time(hour:0, min:15)
 }
 var u = DateWithTime()
 print(u.date.year)

**ネスト型 [#eca87b6c]
 struct SimpleTime {
   var hourr, min: Int
   init(_ hour:Int, _ min:Int) {
     self.hour = hour
     self.min = min
   }
 }
 struct PointOfTime {
   struct Date { var year, month, day: Int }
   typealias Time = SimpleTime
   var date: Date
   var time: TIme
   init(year:Int, month:Int, day:Int, hour:Int, min:Int) {
     date = Date(year:year, month:month, day:day)
     time = Time(hour,min)
   }
 }
 var a = PointOfTime(year:2024,month:11,day:7,hour:14,min:55)
 print(a.date.month)   // 11と表示される
 var b = PointOfTime.Date(year:2022,month:11,day:6)
 print(b.year)         // 2022と表示される
 a.time = PointOfTime.Time(10,21)
 print(a.time.hour)    // 10と表示される

**メソッド [#e7bbea9e]
 struct Time {
   let hour, min : Int
   func add(min:Int) -> Time {
     var m = self.min + min
     var h = self.hour
     if m >= 60 {
       h = (h + m / 60) % 24
       m %= 60
     }
     return Time(hour:h, min:m)
   }
   func toString() -> String {
     let h = hour < 10 ? "0\(hour)" : "\(hour)"   // 2桁の文字列に
     let m = min < 10 ? "0\(min)" : "\(min)"
     return h + ":" + m
   }
 }
 var t1 = Time(hour:22, min:45)
 var t2 = t1.add(140)
 print(t1.toString())   // "22:45" と表示される
 print(t2.toString())   // "01:05" と表示される

構造体の内容を変更するメソッドは、funcの前に mutating というキーワードを置く必要がある。

 struct Clock {
   var hour = 0, min = 0
   mutating func advance(min:Int) {
     let m = self.min + min
     if m >= 60 {
       self.min = m % 60
       let t = self.hour + m / 60
       self.hour = t % 24
     } else {
       self.min = m
     }
   }
   mutating func inc() {
     self.advance(1)
   }
   func toString() -> String { 省略 }
 }
 var tic = Clock(hour:19, min:40)
 tic.advance(19)       // 19:59 と表示される
 tic.inc()
 print(tic.toString()  // 20:00 と表示される

構造体の全インスタンスから呼ばれるようなメソッドは、静的メソッドまたはタイプメソッド (type method) と呼ばれる。
タイプメソッドの内部では、その定義を含む構造体(インスタンスではなく、構造体の型自体を)を表すために self を使う。

initの中で、全てのプロパティが初期化される前にインスタンスメソッドを呼び出すことはできないが、
タイプメソッドを呼び出すことはできる。
 struct Date {
   var year, month, day: Int
   static func isLeap(y: Int) -> Bool {
     return (y % 4 == 0) && (y % 100 != 0 || y % 400 == 0)
   }
   static func daysOfMonth(m:Int, year:Int) -> Int {
     switch m {
       case 2: return isLeap(year) ? 29 : 28     // self.isLeap(year)と記述してもよい
       case 4,6,9,11: return 30
       default: return 31
     }
   }
 }
 print(Date.isLoop(2000))                // true が表示される
 print(Date.daysOfMonth(2, year:2000))   // 29 が表示される

**プロパティ [#sdaeba31]

タイププロパティは、定義の先頭に static というキーワードを付ける。
タイププロパティはその構造体全体に関係する情報を表す。  

 struct DateWithString {
   let string: String
   let year, month, day: Int
   static let mons = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
   static var longFormat = false
   init(_ y:Int, _ m:Int, _ d:Int) {
     year = y; month = m; day = d
     string = DateWithString.longFormat
                ? DateWithString.longString(y,m,d)
                : DateWithString.shortString(y,m,d)
   }
   static func twoDigits(n:Int) -> String {
     let i = n % 100
     return i < 10 ? "0\(i)" : "\(i)"
   }
   static func longString(y:Int, _ m:Int, _ d:Int) -> String {
     return "\(y)-" + twoDigits(m) + "-" + twoDigits(d)
   }
   static func shortString(y:Iint, _ m:Int, _ d:Int) -> String {
     return twoDigits(d) + mons[m-1] + twoDigits(y%100)
   }
 }
 let a = DateWithString(2025,1,20)    // longFormat = false
 print(a.string)                      // "20Jan25"と表示される
 DateWithtstring.longFormat = true
 let b = DateWithString(2025,1,21)
 print(b.string)                      // "2025-01-20"と表示される

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS