Swift 類和結構體

類和結構體

  • 一、結構體和類對比
    • 1、類型定義的語法
    • 2、結構體和類的實例
    • 3、屬性訪問
    • 4、結構體類型的成員逐一構造器
  • 二、結構體和枚舉是值類型
  • 三、類是引用類型
    • 1、恒等運算符
    • 2、指針

結構體和類作為一種通用而又靈活的結構,成為了人們構建代碼的基礎。你可以使用定義常量、變量和函數的語法,為你的結構體和類定義屬性、添加方法。

與其他編程語言所不同的是,Swift 并不要求你為自定義的結構體和類的接口與實現代碼分別創建文件。你只需在單一的文件中定義一個結構體或者類,系統將會自動生成面向其它代碼的外部接口。

注意

通常一個類的實例被稱為對象。然而相比其他語言,Swift 中結構體和類的功能更加相近,本章中所討論的大部分功能都可以用在結構體或者類上。因此,這里會使用實例這個更通用的術語。

一、結構體和類對比

Swift 中結構體和類有很多共同點。兩者都可以:

  • 定義屬性用于存儲值
  • 定義方法用于提供功能
  • 定義下標操作用于通過下標語法訪問它們的值
  • 定義構造器用于設置初始值
  • 通過擴展以增加默認實現之外的功能
  • 遵循協議以提供某種標準功能

與結構體相比,類還有如下的附加功能:

  • 繼承允許一個類繼承另一個類的特征
  • 類型轉換允許在運行時檢查和解釋一個類實例的類型
  • 析構器允許一個類實例釋放任何其所被分配的資源
  • 引用計數允許對一個類的多次引用

類支持的附加功能是以增加復雜性為代價的。作為一般準則,優先使用結構體,因為他們更容易理解,僅在適當或必要時才使用類。實際上,這意味著你的大多數自定義數據類型都會是結構體和枚舉。

1、類型定義的語法

結構體和類有著相似的定義方式。你通過 struct 關鍵字引入結構體,通過 class 關鍵字引入類,并將它們的具體定義放在一對大括號中:

struct SomeStructure {// 在這里定義結構體
}
class SomeClass {// 在這里定義類
}

注意
每當你定義一個新的結構體或者類時,你都是定義了一個新的 Swift 類型。請使用 UpperCamelCase這種方式來命名類型(如這里的 SomeClassSomeStructure ),以便符合標準 Swift 類型的大寫命名風格(如 StringIntBool)。請使用 lowerCamelCase 這種方式來命名屬性和方法(如 frameRateincrementCount),以便和類型名區分。

以下是定義結構體和定義類的示例:

struct Resolution {var width = 0var height = 0
}
class VideoMode {var resolution = Resolution()var interlaced = falsevar frameRate = 0.0var name: String?
}

在上面的示例中定義了一個名為 Resolution 的結構體,用來描述基于像素的分辨率。這個結構體包含了名為 widthheight 的兩個存儲屬性。存儲屬性是與結構體或者類綁定的,并存儲在其中的常量或變量。當這兩個屬性被初始化為整數 0 的時候,它們會被推斷為 Int 類型。

在上面的示例還定義了一個名為 VideoMode 的類,用來描述視頻顯示器的某個特定視頻模式。這個類包含了四個可變的存儲屬性。第一個, resolution,被初始化為一個新的 Resolution 結構體的實例,屬性類型被推斷為 Resolution。新 VideoMode 實例同時還會初始化其它三個屬性,它們分別是初始值為 falseinterlaced(意為“非隔行視頻”),初始值為 0.0frameRate,以及值為可選 Stringname。因為 name 是一個可選類型,它會被自動賦予一個默認值 nil,意為“沒有 name 值”。

2、結構體和類的實例

Resolution 結構體和 VideoMode 類的定義僅描述了什么是 ResolutionVideoMode。它們并沒有描述一個特定的分辨率(resolution)或者視頻模式(video mode)。為此,你需要創建結構體或者類的一個實例。

創建結構體和類實例的語法非常相似:

let someResolution = Resolution()
let someVideoMode = VideoMode()

結構體和類都使用構造器語法來創建新的實例。構造器語法的最簡單形式是在結構體或者類的類型名稱后跟隨一對空括號,如 Resolution()VideoMode()。通過這種方式所創建的類或者結構體實例,其屬性均會被初始化為默認值。構造過程 章節會對類和結構體的初始化進行更詳細的討論。

3、屬性訪問

你可以通過使用點語法訪問實例的屬性。其語法規則是,實例名后面緊跟屬性名,兩者以點號(.)分隔,不帶空格:

print("The width of someResolution is \(someResolution.width)")
// 打印 "The width of someResolution is 0"

在上面的例子中,someResolution.width 引用 someResolutionwidth 屬性,返回 width 的初始值 0

你也可以訪問子屬性,如 VideoModeresolution 屬性的 width 屬性:

print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// 打印 "The width of someVideoMode is 0"

你也可以使用點語法為可變屬性賦值:

someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// 打印 "The width of someVideoMode is now 1280"

4、結構體類型的成員逐一構造器

所有結構體都有一個自動生成的成員逐一構造器,用于初始化新結構體實例中成員的屬性。新實例中各個屬性的初始值可以通過屬性的名稱傳遞到成員逐一構造器之中:

let vga = Resolution(width: 640, height: 480)

注意:
與結構體不同,類實例沒有默認的成員逐一構造器。

二、結構體和枚舉是值類型

值類型是這樣一種類型,當它被賦值給一個變量、常量或者被傳遞給一個函數的時候,其值會被拷貝。

在之前的章節中,你已經大量使用了值類型。實際上,Swift 中所有的基本類型:整數(integer)、浮點數(floating-point number)、布爾值(boolean)、字符串(string)、數組(array)和字典(dictionary),都是值類型,其底層也是使用結構體實現的。

Swift 中所有的結構體和枚舉類型都是值類型。這意味著它們的實例,以及實例中所包含的任何值類型的屬性,在代碼中傳遞的時候都會被復制。

注意

標準庫定義的集合,例如數組,字典和字符串,都對復制進行了優化以降低性能成本。新集合不會立即復制,而是跟原集合共享同一份內存,共享同樣的元素。在集合的某個副本要被修改前,才會復制它的元素。而你在代碼中看起來就像是立即發生了復制。

請看下面這個示例,其使用了上一個示例中的 Resolution 結構體:

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd

在以上示例中,聲明了一個名為 hd 的常量,其值為一個初始化為全高清視頻分辨率(1920 像素寬,1080 像素高)的 Resolution 實例。

然后示例中又聲明了一個名為 cinema 的變量,并將 hd 賦值給它。因為 Resolution 是一個結構體,所以會先創建一個現有實例的副本,然后將副本賦值給 cinema 。盡管 hdcinema 有著相同的寬(width)和高(height),但是在幕后它們是兩個完全不同的實例。

下面,為了符合數碼影院放映的需求(2048 像素寬,1080 像素高),cinemawidth 屬性被修改為稍微寬一點的 2K 標準:

cinema.width = 2048

查看 cinemawidth 屬性,它的值確實改為了 2048

print("cinema is now  \(cinema.width) pixels wide")
// 打印 "cinema is now 2048 pixels wide"

然而,初始的 hd 實例中 width 屬性還是 1920

print("hd is still \(hd.width) pixels wide")
// 打印 "hd is still 1920 pixels wide"

hd 賦值給 cinema 時,hd 中所存儲的值會拷貝到新的 cinema 實例中。結果就是兩個完全獨立的實例包含了相同的數值。由于兩者相互獨立,因此將 cinemawidth 修改為 2048 并不會影響 hd 中的 width 的值,如下圖所示:
在這里插入圖片描述
枚舉也遵循相同的行為準則:

enum CompassPoint {case north, south, east, westmutating func turnNorth() {self = .north}
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()
print("The current direction is \(currentDirection)")
print("The remembered direction is \(rememberedDirection)")
// 打印 "The current direction is north"
// 打印 "The remembered direction is west"

rememberedDirection 被賦予了 currentDirection 的值,實際上它被賦予的是值的一個拷貝。賦值過程結束后再修改 currentDirection 的值并不影響 rememberedDirection 所儲存的原始值的拷貝。

三、類是引用類型

與值類型不同,引用類型在被賦予到一個變量、常量或者被傳遞到一個函數時,其值不會被拷貝。因此,使用的是已存在實例的引用,而不是其拷貝。

請看下面這個示例,其使用了之前定義的 VideoMode 類:

let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

以上示例中,聲明了一個名為 tenEighty 的常量,并讓其引用一個 VideoMode 類的新實例。它的視頻模式(video mode)被賦值為之前創建的 HD 分辨率(1920*1080)的一個拷貝。然后將它設置為隔行視頻,名字設為 “1080i”,并將幀率設置為 25.0 幀每秒。

接下來,將 tenEighty 賦值給一個名為 alsoTenEighty 的新常量,并修改 alsoTenEighty 的幀率:

let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0

因為類是引用類型,所以 tenEightalsoTenEight 實際上引用的是同一個 VideoMode 實例。換句話說,它們是同一個實例的兩種叫法,如下圖所示:
在這里插入圖片描述
通過查看 tenEightyframeRate 屬性,可以看到它正確地顯示了底層的 VideoMode 實例的新幀率 30.0

print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// 打印 "The frameRate property of theEighty is now 30.0"

這個例子也顯示了為何引用類型更加難以理解。如果 tenEightyalsoTenEighty 在你代碼中的位置相距很遠,那么就很難找到所有修改視頻模式的地方。無論在哪使用 tenEighty,你都要考慮使用 alsoTenEighty 的代碼,反之亦然。相反,值類型就更容易理解了,因為你的源碼中與同一個值交互的代碼都很近。

需要注意的是 tenEightyalsoTenEighty 被聲明為常量而不是變量。然而你依然可以改變 tenEighty.frameRatealsoTenEighty.frameRate,這是因為 tenEightyalsoTenEighty 這兩個常量的值并未改變。它們并不“存儲”這個 VideoMode 實例,而僅僅是對 VideoMode 實例的引用。所以,改變的是底層 VideoMode 實例的 frameRate 屬性,而不是指向 VideoMode 的常量引用的值。

1、恒等運算符

因為類是引用類型,所以多個常量和變量可能在幕后同時引用同一個類實例。(對于結構體和枚舉來說,這并不成立。因為它們作為值類型,在被賦予到常量、變量或者傳遞到函數時,其值總是會被拷貝。)

判定兩個常量或者變量是否引用同一個類實例有時很有用。為了達到這個目的,Swift 提供了兩個恒等運算符:

  • 相同(===
  • 不相同(!==

使用這兩個運算符檢測兩個常量或者變量是否引用了同一個實例:

if tenEighty === alsoTenEighty {print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// 打印 "tenEighty and alsoTenEighty refer to the same VideoMode instance."

請注意,“相同”(用三個等號表示,===)與“等于”(用兩個等號表示,==)的不同。“相同”表示兩個類類型(class type)的常量或者變量引用同一個類實例。“等于”表示兩個實例的值“相等”或“等價”,判定時要遵照設計者定義的評判標準。

當在定義你的自定義結構體和類的時候,你有義務來決定判定兩個實例“相等”的標準

2、指針

如果你有 C,C++ 或者 Objective-C 語言的經驗,那么你也許會知道這些語言使用指針來引用內存中的地址。Swift 中引用了某個引用類型實例的常量或變量,與 C 語言中的指針類似,不過它并不直接指向某個內存地址,也不要求你使用星號(*)來表明你在創建一個引用。相反,Swift 中引用的定義方式與其它的常量或變量的一樣。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/15353.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15353.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/15353.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python mp3轉mp4工具

成品UI 安裝moviepy庫 pip install moviepy 轉換demo from moviepy.editor import *# 創建一個顏色剪輯,時長與音頻相同 audioclip AudioFileClip(r"C:\Users\Administrator\PycharmProjects\pythonProject44\test4\趙照 - 燈塔守望人.mp3") videoclip…

node-nass安裝踩坑

編譯DSS的前端,用1.1.4編譯,沒有問題,用1.1.1版本就有問題,一直是node-gyp有問題,怎么也解決了不了。 后來檢查發現,是因為要安裝node-nass才導致出現node-gyp的問題。 而1.1.4沒問題,是因為我…

頭歌c語言實驗答案

由于頭歌C語言實驗的具體內容和題目可能隨時間變化,我無法直接提供特定實驗的完整答案。但我可以基于參考文章中的內容和結構,給出一個通用的回答格式,并結合相關信息進行說明。 通用回答格式 實驗名稱和描述 實驗名稱:頭歌C語言…

用Python Pygame做的一些好玩的小游戲

有些游戲的代碼比較長就不公布了 1.簡簡單單 1.瘋狂的雞哥 你要準備的圖片: 命名為:ji.png 代碼: import pygame import random as r pygame.init() pygame.display.set_caption(aaa) pm pygame.display.set_mode((800,600))class Ls(py…

Java進階學習筆記15——接口概述

認識接口: Java提供了一個關鍵字Interface,用這個關鍵字我們可以定義一個特殊的結構:接口。 接口不能創建對象。 注意:接口不能創建對象,接口是用來被類實現(implements)的,實現接口…

中國電子學會(CEIT)2023年05月真題C語言軟件編程等級考試三級(含詳細解析答案)

中國電子學會(CEIT)考評中心歷屆真題(含解析答案) C語言軟件編程等級考試三級 2023年05月 編程題五道 總分:100分一、找和為K的兩個元素(20分) 在一個長度為n (n < 1000)的整數序列中,判斷是否存在某兩個元素之和為k。 時間限制: 1000 內存限制: 65536 輸入 …

基于Spring Boot的高校圖書館管理系統

項目和論文都有企鵝號2583550535 基于Spring Boot的圖書館管理系統||圖書管理系統_嗶哩嗶哩_bilibili 第1章 緒論... 1 1.1 研究背景和意義... 1 1.2 國內外研究現狀... 1 第2章 相關技術概述... 2 2.1 后端開發技術... 2 2.1.1 SpringBoot 2 2.1.2 MySQL.. 2 2.1.3 My…

unity中如何插入網頁

在Unity中插入自己的網頁通常是通過使用Unity的WebGL構建目標和HTML頁面來實現的。以下是一些步驟&#xff1a; 構建你的Unity項目為WebGL&#xff1a;在Unity中&#xff0c;選擇Build Settings&#xff08;構建設置&#xff09;&#xff0c;將Platform&#xff08;平臺&#x…

vr商品全景展示場景編輯軟件的優點

3D模型展示網站搭建編輯器以強大的3D編輯引擎和逼真的渲染效果&#xff0c;讓您輕松實現模型展示的優化。讓用戶通過簡單的操作&#xff0c;就能滿足個人/設計師/商戶多樣化展示的需求&#xff0c;讓您的模型成為獨一無二的杰作。 3D模型展示網站搭建編輯器采用國內領先的實時互…

java繼承使用細節二

構造器 主類是無參構造器時會默認調用 public graduate() {// TODO Auto-generated constructor stub也就是說我這里要用構造器會直接調用父類。它是默認看不到的 &#xff0c;System.out.println("graduate");} 但當主類是有參構造器如 public father_(int s,doubl…

c語言:將小寫字母轉換為大寫字母

//將小寫字母轉換為大寫字母 #include <stdio.h> #include <ctype.h> int main() { char arr[]"you are low"; int i0; while(arr[i]) { if(islower(arr[i])) { arr[i]arr[i]-32; } i; } printf("%s\n",arr); return 0; }

微調Llama3實現在線搜索引擎和RAG檢索增強生成功能

視頻中所出現的代碼 Tavily SearchRAG 微調Llama3實現在線搜索引擎和RAG檢索增強生成功能&#xff01;打造自己的perplexity和GPTs&#xff01;用PDF實現本地知識庫_嗶哩嗶哩_bilibili 一.準備工作 1.安裝環境 conda create --name unsloth_env python3.10 conda activate …

周末總結(2024/05/25)

工作 人際關系核心實踐&#xff1a; 要學會隨時回應別人的善意。執行時間控制在5分鐘以內 堅持每天早會打招呼 工作上的要點 現狀&#xff08;接受破爛現狀&#xff0c;改變狀態&#xff09; - 這周使用和執行了生產環境發布流程(2天&#xff09;&#xff0c;2天時間在寫Java…

大膽預測:計算機將要回暖

中概財報集體亮眼 雖然最近幾天恒指&#xff08;港股&#xff09;稍有回落&#xff0c;但年線仍有 9% 的上漲。 過去三年&#xff0c;恒指分別下跌 14.08%、15.46% 和 13.82%。 而在近期&#xff0c;國內各大互聯網都公布了財報&#xff0c;別看各個大廠的作妖不斷&#xff0c;…

[前端|vue] v-if 和v-show的區別,為什么功能會類似

v-if 和 v-show 都是 Vue 中用于條件渲染的指令&#xff0c;但它們之間存在幾個關鍵區別&#xff0c;這些區別導致了它們在不同場景下的適用性也有所不同&#xff1a; v-if 的特點&#xff1a; 條件渲染&#xff1a;v-if 是一個動態的條件渲染指令&#xff0c;它會根據表達式的…

dubbo復習:(8)使用sentinel對服務進行降級

一、下載sentinel-dashboard控制臺應用并在8080端口啟動 二、項目添加springboot 和dubbo相關依賴&#xff08;降級規則并未持久化&#xff0c;如果需要持久化&#xff0c;如果需要持久化降級規則&#xff0c;只需增加nacos相關依賴并在nacos中進行配置&#xff0c;然后配置app…

會話機制:Session

1、什么是會話&#xff1a; 會話對應的英語單詞&#xff1a;session 用戶打開瀏覽器&#xff0c;進行一系列操作&#xff0c;然后最終將瀏覽器關閉&#xff0c;這個整個過程叫做&#xff1a;一次會話。會話在服務器端也有一個對應的java對象&#xff0c;這個java對象叫做&…

使用Python Tkinter創建GUI應用程序

大家好&#xff0c;當我們談及使用Python Tkinter創建GUI應用程序時&#xff0c;我們涉及的不僅是技術和代碼&#xff0c;更是關于創造力和用戶體驗的故事。Tkinter作為Python標準庫中最常用的GUI工具包&#xff0c;提供了豐富的功能和靈活的接口&#xff0c;讓開發者能夠輕松地…

每日一題(4)——String連接,替換,比較,查找等

主要是一些字符串的連接&#xff0c; 替換&#xff0c;比較&#xff0c;去首尾空格&#xff0c;查找等操作&#xff1b; class ZiFu{public static void main(String []args){String s1"hello world";String s2new String("hello,world");s2" "…

Vue3判斷變量和對象不為null和undefined

Vue3判斷變量和對象不為null和undefined 一、判斷變量二、判斷對象 一、判斷變量 在 Vue 3 中&#xff0c;你可以使用 JavaScript 提供的常規方式來檢查變量是否不為 null 和不為 undefined。你可以分別使用嚴格不等運算符 ! 來比較變量是否不為 null 和不為 undefined。以下是…