Proses pembinaan pantas


Proses pembinaan ialah proses penyediaan untuk menggunakan contoh kelas, struktur atau jenis penghitungan. Proses ini termasuk menetapkan nilai awal untuk setiap harta dalam contoh dan melaksanakan tugas penyediaan dan permulaan yang diperlukan.

Pembina Swift menggunakan kaedah init().

Tidak seperti pembina dalam Objektif-C, pembina Swift tidak perlu mengembalikan nilai Tugas utama mereka adalah untuk memastikan kejadian baharu dimulakan dengan betul sebelum ia digunakan buat kali pertama.

Tis kelas juga boleh melakukan kerja membersihkan memori sebelum tika kelas dikeluarkan dengan mentakrifkan penyahinisial.



Penugasan awal atribut yang disimpan

Apabila contoh kelas dan struktur dicipta, nilai awal yang sesuai mesti ditetapkan untuk semua atribut yang disimpan .

Apabila sifat yang disimpan diperuntukkan dalam pembina, nilainya ditetapkan secara langsung dan tiada pemerhati harta dicetuskan.

Proses penetapan harta simpanan dalam pembina:

  • Buat nilai awal.

  • Menentukan nilai sifat lalai dalam definisi harta.

  • Mulakan contoh dan panggil kaedah init().


Pembina

Pembina dipanggil apabila mencipta tika baharu bagi jenis tertentu. Bentuk termudahnya adalah serupa dengan kaedah contoh tanpa sebarang parameter, dinamakan sempena kata kunci init.

Sintaks

init()
{
    // 实例化后执行的代码
}

Instance

Struktur berikut mentakrifkan init pembina tanpa parameter, dan memulakan nilai atribut yang disimpan panjang dan lebar kepada 6. dan 12:

struct rectangle {
    var length: Double
    var breadth: Double
    init() {
        length = 6
        breadth = 12
    }
}
var area = rectangle()
print("矩形面积为 \(area.length*area.breadth)")

Output pelaksanaan program di atas ialah:

矩形面积为 72.0

Nilai atribut lalai

Kami boleh menetapkan nilai awal untuk atribut yang disimpan dalam pembina; , anda boleh menetapkan nilai lalai untuk harta apabila ia diisytiharkan.

Menggunakan nilai lalai boleh menjadikan pembina anda lebih mudah dan jelas, dan jenis sifat boleh disimpulkan secara automatik daripada nilai lalai.

Dalam contoh berikut, kami menetapkan nilai lalai untuk atribut apabila ia diisytiharkan:

struct rectangle {
	// 设置默认值
    var length = 6
    var breadth = 12
}
var area = rectangle()
print("矩形的面积为 \(area.length*area.breadth)")

Hasil keluaran pelaksanaan program di atas ialah:

矩形面积为 72

Parameter pembinaan

Anda boleh menyediakan parameter pembinaan apabila mentakrifkan pembina init(), seperti ditunjukkan di bawah:

struct Rectangle {
    var length: Double
    var breadth: Double
    var area: Double
    
    init(fromLength length: Double, fromBreadth breadth: Double) {
        self.length = length
        self.breadth = breadth
        area = length * breadth
    }
    
    init(fromLeng leng: Double, fromBread bread: Double) {
        self.length = leng
        self.breadth = bread
        area = leng * bread
    }
}

let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("面积为: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)
print("面积为: \(are.area)")

Output pelaksanaan program di atas ialah:

面积为: 72.0
面积为: 432.0

Parameter dalaman dan luaran Nama

adalah sama dengan parameter fungsi dan kaedah Terdapat juga nama parameter yang digunakan di dalam pembina dan nama parameter luaran yang digunakan semasa memanggil pembina.

Walau bagaimanapun, pembina tidak mempunyai nama yang boleh dibezakan sebelum kurungan seperti fungsi dan kaedah. Oleh itu, apabila memanggil pembina, pembina yang akan dipanggil ditentukan terutamanya oleh nama parameter dan jenis dalam pembina.

Jika anda tidak memberikan nama luaran untuk parameter semasa mentakrifkan pembina, Swift akan menjana nama luaran secara automatik untuk setiap parameter pembina yang sama dengan nama dalaman.

struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}

// 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)

print("red 值为: \(magenta.red)")
print("green 值为: \(magenta.green)")
print("blue 值为: \(magenta.blue)")

// 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器
let halfGray = Color(white: 0.5)
print("red 值为: \(halfGray.red)")
print("green 值为: \(halfGray.green)")
print("blue 值为: \(halfGray.blue)")

Output pelaksanaan program di atas ialah:

red 值为: 1.0
green 值为: 0.0
blue 值为: 1.0
red 值为: 0.5
green 值为: 0.5
blue 值为: 0.5

Tiada parameter nama luaran

Jika anda tidak mahu memberikan nama luaran untuk parameter pembina, anda boleh menggunakan garis bawah _ untuk memaparkan nama luaran yang menerangkannya.

struct Rectangle {
    var length: Double
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    //不提供外部名字
    init(_ area: Double) {
        length = area
    }
}

// 调用不提供外部名字
let rectarea = Rectangle(180.0)
print("面积为: \(rectarea.length)")

// 调用不提供外部名字
let rearea = Rectangle(370.0)
print("面积为: \(rearea.length)")

// 调用不提供外部名字
let recarea = Rectangle(110.0)
print("面积为: \(recarea.length)")

Hasil keluaran pelaksanaan program di atas ialah:

面积为: 180.0
面积为: 370.0
面积为: 110.0

Jenis atribut pilihan

Jika jenis tersuai anda mengandungi atribut tersimpan yang secara logik membenarkan nilai nol, anda perlu mentakrifkannya sebagai jenis pilihan (jenis pilihan) Pilih jenis atribut).

Apabila harta yang disimpan diisytiharkan sebagai pilihan, ia akan dimulakan secara automatik kepada sifar.

struct Rectangle {
    var length: Double?
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    
    init(_ area: Double) {
        length = area
    }
}

let rectarea = Rectangle(180.0)
print("面积为:\(rectarea.length)")

let rearea = Rectangle(370.0)
print("面积为:\(rearea.length)")

let recarea = Rectangle(110.0)
print("面积为:\(recarea.length)")

Output pelaksanaan program di atas ialah:

面积为:Optional(180.0)
面积为:Optional(370.0)
面积为:Optional(110.0)

Ubah suai atribut malar semasa proses pembinaan

Selagi nilai pemalar boleh ditentukan sebelum tamat proses pembinaan, anda boleh Mengubah suai nilai harta tetap pada bila-bila masa semasa pembinaan.

Untuk contoh kelas, atribut tetapnya hanya boleh diubah suai semasa proses pembinaan kelas yang mentakrifkannya;

Walaupun atribut panjang kini adalah pemalar, kita masih boleh menetapkan nilainya dalam pembina kelasnya:

struct Rectangle {
    let length: Double?
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    
    init(_ area: Double) {
        length = area
    }
}

let rectarea = Rectangle(180.0)
print("面积为:\(rectarea.length)")

let rearea = Rectangle(370.0)
print("面积为:\(rearea.length)")

let recarea = Rectangle(110.0)
print("面积为:\(recarea.length)")

Output pelaksanaan program di atas ialah:

面积为:Optional(180.0)
面积为:Optional(370.0)
面积为:Optional(110.0)

Pembina lalai

Pembina lalai hanya akan mencipta contoh dengan semua nilai atribut ditetapkan kepada nilai lalai:

Dalam contoh berikut, semua atribut dalam kelas ShoppingListItem mempunyai lalai values ​​, dan ia adalah kelas asas tanpa kelas induk, ia secara automatik akan memperoleh pembina lalai yang boleh menetapkan nilai lalai untuk semua sifat

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()


print("名字为: \(item.name)")
print("数理为: \(item.quantity)")
print("是否付款: \(item.purchased)")

Hasil keluaran pelaksanaan program di atas ialah:

名字为: nil
数理为: 1
是否付款: false

struktur Pemula ahli demi ahli

Jika struktur menyediakan nilai lalai untuk semua sifat yang disimpan dan tidak menyediakan pemula tersuai dengan sendirinya, mereka boleh mendapatkan secara automatik ahli demi ahli pemula.

Apabila kita memanggil pembina ahli demi ahli, kita lulus nama parameter yang sama dengan nama atribut ahli untuk menyelesaikan tugasan awal atribut ahli.

Contoh berikut mentakrifkan struktur Segiempat, yang mengandungi dua atribut panjang dan lebar. Swift secara automatik boleh menyimpulkan jenis Double bagi kedua-dua sifat ini berdasarkan tugasan awal mereka 100.0 dan 200.0.

struct Rectangle {
    var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)

print("矩形的面积: \(area.length)")
print("矩形的面积: \(area.breadth)")

Memandangkan kedua-dua sifat yang disimpan mempunyai nilai lalai, struktur Rectangle secara automatik mendapat init pembina ahli demi ahli(lebar:tinggi:). Anda boleh menggunakan ini untuk membuat kejadian baharu Rectangle.

Output pelaksanaan program di atas ialah:

名字为: nil
矩形的面积: 24.0
矩形的面积: 32.0

Proksi pembina jenis nilai

Pembina boleh melengkapkan sebahagian daripada proses pembinaan contoh dengan memanggil pembina lain. Proses ini dipanggil delegasi pembina, dan ia mengurangkan pertindihan kod merentas berbilang pembina.

Dalam contoh berikut, struktur Rect memanggil proses pembinaan Saiz dan Titik:

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}


// origin和size属性都使用定义时的默认值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0):
let basicRect = Rect()
print("Size 结构体初始值: \(basicRect.size.width, basicRect.size.height) ")
print("Rect 结构体初始值: \(basicRect.origin.x, basicRect.origin.y) ")

// 将origin和size的参数值赋给对应的存储型属性
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))

print("Size 结构体初始值: \(originRect.size.width, originRect.size.height) ")
print("Rect 结构体初始值: \(originRect.origin.x, originRect.origin.y) ")


//先通过center和size的值计算出origin的坐标。
//然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))

print("Size 结构体初始值: \(centerRect.size.width, centerRect.size.height) ")
print("Rect 结构体初始值: \(centerRect.origin.x, centerRect.origin.y) ")

Hasil keluaran pelaksanaan program di atas ialah:

Size 结构体初始值: (0.0, 0.0) 
Rect 结构体初始值: (0.0, 0.0) 
Size 结构体初始值: (5.0, 5.0) 
Rect 结构体初始值: (2.0, 2.0) 
Size 结构体初始值: (3.0, 3.0) 
Rect 结构体初始值: (2.5, 2.5)

Pembina peraturan proksi

值类型类类型
不支持继承,所以构造器代理的过程相对简单,因为它们只能代理给本身提供的其它构造器。 你可以使用self.init在自定义的构造器中引用其它的属于相同值类型的构造器。它可以继承自其它类,这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。

Pewarisan kelas dan proses pembinaan

Swift menyediakan dua jenis pembina kelas untuk memastikan sifat yang disimpan dalam semua kejadian kelas boleh memperoleh nilai awal Ia adalah pembina yang ditetapkan dan pembina Kemudahan.

指定构造器便利构造器
类中最主要的构造器类中比较次要的、辅助型的构造器
初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入的实例。
每一个类都必须拥有至少一个指定构造器只在必要的时候为类提供便利构造器
Init(parameters) {
    statements
}
convenience init(parameters) {
      statements
}

Instance pembina yang ditentukan

class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}
class subClass : mainClass {
    var no2 : Int // 新的子类存储变量
    init(no1 : Int, no2 : Int) {
        self.no2 = no2 // 初始化
        super.init(no1:no1) // 初始化超类
    }
}

let res = mainClass(no1: 10)
let res2 = subClass(no1: 10, no2: 20)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

Hasil keluaran pelaksanaan program di atas ialah:

res 为: 10
res 为: 10
res 为: 20

Contoh pembina kemudahan

class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}

class subClass : mainClass {
    var no2 : Int
    init(no1 : Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    // 便利方法只需要一个参数
    override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}
let res = mainClass(no1: 20)
let res2 = subClass(no1: 30, no2: 50)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

Hasil output pelaksanaan program di atas ialah:

res 为: 20
res2 为: 30
res2 为: 50

Warisan dan lebihan pembina

Subkelas dalam Swift tidak mewarisi pembina kelas induk secara lalai.

Pembina kelas induk hanya diwarisi apabila ia pasti dan selamat.

Apabila anda mengatasi pembina yang ditetapkan kelas induk, anda perlu menulis pengubah ganti.

class SuperClass {
    var corners = 4
    var description: String {
        return "\(corners) 边"
    }
}
let rectangle = SuperClass()
print("矩形: \(rectangle.description)")

class SubClass: SuperClass {
    override init() {  //重载构造器
        super.init()
        corners = 5
    }
}

let subClass = SubClass()
print("五角型: \(subClass.description)")

Output pelaksanaan program di atas ialah:

矩形: 4 边
五角型: 5 边

Instance pembina dan pembina kemudahan yang ditentukan

Contoh berikut akan menunjukkan pembina yang ditetapkan dan pembina kemudahan dalam operasi Pewarisan pembina dan pembina automatik.

Ia mentakrifkan hierarki kelas yang mengandungi dua kelas, MainClass dan SubClass, dan akan menunjukkan cara pembina mereka berinteraksi.

class MainClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "[匿名]")
    }
}
let main = MainClass(name: "php")
print("MainClass 名字为: \(main.name)")

let main2 = MainClass()
print("没有对应名字: \(main2.name)")

class SubClass: MainClass {
    var count: Int
    init(name: String, count: Int) {
        self.count = count
        super.init(name: name)
    }
    
    override convenience init(name: String) {
        self.init(name: name, count: 1)
    }
}

let sub = SubClass(name: "php")
print("MainClass 名字为: \(sub.name)")

let sub2 = SubClass(name: "php", count: 3)
print("count 变量: \(sub2.count)")

Hasil keluaran pelaksanaan program di atas ialah:

MainClass 名字为: php
没有对应名字: [匿名]
MainClass 名字为: php
count 变量: 3

Pembina kelas yang gagal

Jika objek jenis kelas, struktur atau penghitungan, dalam Ia mungkin gagal semasa pembinaan dirinya sendiri, jadi tentukan pemula yang gagal untuknya.

Mungkin sebab kegagalan pemulaan pembolehubah adalah:

  • Nilai parameter tidak sah yang dihantar masuk.

  • Sumber luaran yang diperlukan tiada.

  • Syarat khusus tidak dipenuhi.

Untuk mengendalikan situasi yang mungkin gagal semasa proses pembinaan ini dengan betul.

Anda boleh menambah satu atau lebih pemula yang gagal pada takrif kelas, struktur atau jenis penghitungan. Sintaksnya ialah menambah tanda soal (init?) selepas kata kunci init.

Contoh

Dalam contoh berikut, struktur bernama Haiwan ditakrifkan, yang mempunyai atribut tetap jenis String bernama spesies.

Pada masa yang sama, struktur juga mentakrifkan pembina yang gagal dengan spesies parameter jenis String. Pemula yang gagal ini digunakan untuk menyemak sama ada parameter masuk ialah rentetan kosong Jika ia rentetan kosong, pemula yang gagal gagal membina objek, jika tidak, ia akan berjaya.

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

//通过该可失败构造器来构建一个Animal的对象,并检查其构建过程是否成功
// someCreature 的类型是 Animal? 而不是 Animal
let someCreature = Animal(species: "长颈鹿")

// 打印 "动物初始化为长颈鹿"
if let giraffe = someCreature {
    print("动物初始化为\(giraffe.species)")
}

Output pelaksanaan program di atas ialah:

动物初始化为长颈鹿

Pembina jenis penghitungan yang gagal

Anda boleh membina pembina yang gagal dengan satu atau lebih parameter Kontena untuk mendapatkan penghitungan tertentu ahli daripada jenis penghitungan.

Contoh

Dalam contoh berikut, jenis penghitungan bernama TemperatureUnit ditakrifkan. Ia mengandungi tiga ahli penghitungan yang mungkin (Kelvin, Celsius dan Fahrenheit) dan pemula yang gagal yang digunakan untuk mencari ahli penghitungan yang sepadan dengan nilai Aksara:

enum TemperatureUnit {
	// 开尔文,摄氏,华氏
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}


let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("这是一个已定义的温度单位,所以初始化成功。")
}

let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("这不是一个已定义的温度单位,所以初始化失败。")
}

Hasil output pelaksanaan program di atas Untuk:

这是一个已定义的温度单位,所以初始化成功。
这不是一个已定义的温度单位,所以初始化失败。

Pengasa kelas yang gagal

Pengasas jenis nilai yang gagal (seperti struktur atau jenis penghitungan), bila dan di mana kegagalan pembinaan dicetuskan Tiada sekatan pada tingkah laku.

Walau bagaimanapun, pemula kelas yang gagal hanya boleh mencetuskan gelagat kegagalan selepas semua sifat kelas telah dimulakan dan panggilan proksi antara pembina antara semua kelas telah berlaku.

Contoh

Dalam contoh berikut, kelas bernama StudRecord ditakrifkan Oleh kerana atribut studname ialah pemalar, setelah kelas StudRecord berjaya dibina, atribut studname mesti mempunyai bukan nol. nilai.

class StudRecord {
    let studname: String!
    init?(studname: String) {
        self.studname = studname
        if studname.isEmpty { return nil }
    }
}
if let stname = StudRecord(studname: "失败构造器") {
    print("模块为 \(stname.studname)")
}

Hasil keluaran pelaksanaan program di atas ialah:

模块为 失败构造器

Mengatasi pembina yang gagal

Sama seperti pembina lain, anda juga boleh menggunakan pembina subkelas yang gagal. pembina mengatasi pemula gagal kelas asas.

Sebagai alternatif, anda boleh mengatasi pemula yang gagal kelas asas dengan pemula tidak gagal subkelas.

Anda boleh mengatasi pemula yang gagal dengan pemula yang tidak gagal, tetapi sebaliknya tidak berfungsi.

Pemula yang tidak gagal tidak boleh mewakilkan panggilan kepada pemula yang gagal.

Contoh

Contoh berikut menerangkan pembina yang gagal dan tidak gagal:

class Planet {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "[No Planets]")
    }
}
let plName = Planet(name: "Mercury")
print("行星的名字是: \(plName.name)")

let noplName = Planet()
print("没有这个名字的行星: \(noplName.name)")

class planets: Planet {
    var count: Int
    
    init(name: String, count: Int) {
        self.count = count
        super.init(name: name)
    }
    
    override convenience init(name: String) {
        self.init(name: name, count: 1)
    }
}

Hasil output pelaksanaan program di atas ialah:

行星的名字是: Mercury
没有这个名字的行星: [No Planets]

Init pemula yang gagal!

Biasanya kami mentakrifkan pemula yang gagal dengan menambahkan tanda soal (init?) selepas kata kunci init, tetapi anda juga boleh menggunakannya dengan menambah tanda seru selepas cara init untuk menentukan pemula yang gagal. (init!). Contohnya adalah seperti berikut:

struct StudRecord {
    let stname: String
    
    init!(stname: String) {
        if stname.isEmpty {return nil }
        self.stname = stname
    }
}

let stmark = StudRecord(stname: "php")
if let name = stmark {
    print("指定了学生名")
}

let blankname = StudRecord(stname: "")
if blankname == nil {
    print("学生名为空")
}

Hasil output pelaksanaan program di atas ialah:

指定了学生名
学生名为空