Swift

Swift/構造体

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

struct内の変数はプロパティ(property)と呼ばれる。

struct Date {
  var year: Int
  var month: Int
  var day: Int
}

構造体の初期値

初期化に使う手続きがイニシャライザ (initializer) である。 構造体の定義には、各プロパティの初期値を記述しておくことができる(default initializer)。

struct Date {
  var year:Int = 2016  // 型を明記した場合
  var month = 7        // 型を初期値から推測させた場合
  var day = 28
}
var d = Date()
print(d.day)    // 28 と表示される

全項目イニシャライザ

個々のプロパティの値を指定してインスタンスを生成することができる(memberwise initializer)。

var a = Date(year:2016, month:5, day: 13)

構造体は値型であり、代入はコピーによって行われる。 定数に代入した構造体の各プロパティは値を変更できない。

let b = Date(year: 2016, month: 5, day: 13)
b.year = 2017   // エラー

構造体の定数プロパティ

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

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時間制)

イニシャライザの定義

イニシャライザは 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と表示される

複数個のイニシャライザを定義する

関数の定義とは異なり、イニシャライザの定義では第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を定義する。

関数とイニシャライザ表記のまとめ

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

以下に関しては、どちらも指定可能である。

  • 引数に対するvarまたはletの指定
  • inoutの指定 (ただしvar, letとの併用は不可)
  • default値の指定 (ただしinoutとの併用は不可)
  • 可変長引数 (ただしvar, let, inoutとの併用は不可)
  • 定義のオーバーロード

他の構造体を含む構造体

struct DateWithTime {
  var date = Date()
  var time = Time(hour:0, min:15)
}
var u = DateWithTime()
print(u.date.year)

ネスト型

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と表示される

メソッド

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 が表示される

プロパティ

タイププロパティは、定義の先頭に 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
Last-modified: 2016-07-01 (金) 16:35:42 (505d)