Swift基础
本文是个比较简单的学习笔记,更详细的内容见 Swift官方文档
1、相等性比较
Swift标准库用 < 和 == 运算符定义了 >、>=、<=,所以实现 Comparable 的 < 运算符就会自动得到这些运算符的实现,实际上 Comparable 继承自 Equatable,所以 == 运算也是必须实现的,以下是示例代码
struct Point: Comparable, CustomStringConvertible {let x: Intlet y: Intvar description: String {return "Point(\(x), \(y))"}static func ==(lhs: Point, rhs: Point) -> Bool {return lhs.x == rhs.x && lhs.y == rhs.y}static func <(lhs: Point, rhs: Point) -> Bool {return lhs.x < rhs.x && lhs.y < rhs.y}static func + (left: Point, right: Point) -> Point {return Point(x: left.x + right.x, y: left.y + right.y)}
}let a = Point(x: 3, y: 4)
let b = Point(x: 3, y: 4)
let abEqual = (a == b)
a != blet c = Point(x: 2, y: 6)
let d = Point(x: 3, y: 7)
c == d
c < d
c <= d
c > d
c >= dc + dclass Person: Equatable {let name: Stringlet age: Intweak var brother: Person?init(name: String, age: Int) {self.name = nameself.age = age}static func ==(lhs: Person, rhs: Person) -> Bool {return lhs.name == rhs.name}
}let p1 = Person(name: "JJF", age: 33)
let p2 = Person(name: "JZF", age: 36)
var people = [p1, p2]
if let p1Index = people.firstIndex(where: { $0 == p2 }) {print(p1Index)
}//自定义运算符
infix operator +++func +++(lhs: Person, rhs: Person) {lhs.brother = rhsrhs.brother = lhs
}
p1 +++ p2
p1.brother?.name
p2.brother?.name
2、日期和时间
import Foundationlet date = Date.nowlet dateFormatter = DateFormatter()
//dateFormatter.locale = Locale(identifier: "zh_CN")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"// typealias TimeInterval = Double
// A number of seconds.
// TimeInterval 是 Double 类型,单位是秒,可精确到微秒
//时间戳,1970到现在的毫秒数
let timestamp = Int(date.timeIntervalSince1970 * 1000)
print("timestamp = \(timestamp)")//取当前时间的年/月/日/时/分/秒/毫秒
var calendar = Calendar.current
let year = calendar.component(.year, from: date)
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
let milliSecond = calendar.component(.nanosecond, from: date) / 1000_000
print("\(year)-\(String(format: "%02D", month))-\(String(format: "%02D", day)) \(String(format: "%02D", hour)):\(String(format: "%02D", minute)):\(String(format: "%02D", second)).\(String(format: "%03D", milliSecond))")//使用 DateFormatter 格式化时间
print("\(dateFormatter.string(from: date))")let str = "Hello World!"
let start = str.index(str.startIndex, offsetBy: 6)
let end = str.index(str.startIndex, offsetBy: 11)
let substr = String(str[start..<end])
print(substr)
3、处理异常
enum Token {case number(Int)case plus
}class Lexer {enum Error: Swift.Error {case invalidCharacter(Character)}let input: Stringvar position: String.Indexinit(input: String) {self.input = inputself.position = self.input.startIndex}func peek() -> Character? {guard position < input.endIndex else {return nil}return input[position]}func advance() {//断言只在调试模式下生效,发布模式下可使用 precondition(_:_:) 替代assert(position < input.endIndex, "Cannot advance past endIndex!")position = input.index(after: position)}func lex() throws -> [Token] {var tokens = [Token]()while let nextCharacter = peek() {switch nextCharacter {case "0"..."9":tokens.append(.number(getNumber()))case "+":tokens.append(.plus)advance()case " ":advance()default:throw Lexer.Error.invalidCharacter(nextCharacter)}}return tokens}func getNumber() -> Int {var value = 0while let nextCharacter = peek() {switch nextCharacter {case "0"..."9":let digitValue = Int(String(nextCharacter))!value = 10 * value + digitValueadvance()default:return value}}return value}
}class Parser {enum Error: Swift.Error {case unexpectedEndOfInputcase invalidToken(Token)}let tokens: [Token]var position = 0init(tokens: [Token]) {self.tokens = tokens}func nextToken() -> Token? {guard position < tokens.count else {return nil}let token = tokens[position]position += 1return token}func getNumber() throws -> Int {guard let token = nextToken() else {throw Parser.Error.unexpectedEndOfInput}switch token {case .number(let value):return valuecase .plus:throw Parser.Error.invalidToken(token)}}func parse() throws -> Int {var value = try getNumber()while let token = nextToken() {switch token {case .plus:let nextNumber = try getNumber()value += nextNumbercase .number:throw Parser.Error.invalidToken(token)}}return value}
}func evaluate(_ input: String) {print("Evaluating: \(input)")let lexer = Lexer(input: input)
// let tokens = try! lexer.lex()//强制执行可能抛出错误的方法,发生错误时触发陷阱
// guard let tokens = try? lexer.lex() else {
// print("Lexing failed, but I don't know why")
// return
// }do {let tokens = try lexer.lex()print("Lexer ouput: \(tokens)")let parser = Parser(tokens: tokens)let value = try parser.parse()print(value)} catch Lexer.Error.invalidCharacter(let character) {print("Input contained an invalid character: \(character)")} catch Parser.Error.unexpectedEndOfInput {print("Unexpected end of input during parsing")} catch Parser.Error.invalidToken(let token) {print("Invalid token during parsing: \(token)")} catch {print("An error occurred: \(error)")}
}
evaluate("10 + 3 + 5 +")
4、扩展
(1)扩展类/结构体
typealias Velocity = Doubleextension Velocity {var kph: Velocity { return self * 1.60934 }var mph: Velocity { return self }
}protocol Vehicle {var topSpeed: Velocity { get }var numberOfDoors: Int { get }var hasFlatbed: Bool { get }
}struct Car {let make: Stringlet model: Stringlet year: Intlet color: Stringlet nickname: Stringvar gasLevel: Double {willSet {precondition(newValue <= 1.0 && newValue >= 0.0, "New value must between 0 and 1.")}}
}//利用拓展使 Car 实现协议
extension Car: Vehicle {var topSpeed: Velocity { return 180 }var numberOfDoors: Int { return 4 }var hasFlatbed: Bool { return false }
}//利用拓展给 Car 增加初始化方法,这样会保留默认的成员初始化方法
extension Car {init(make: String, model: String, year: Int) {self.init(make: make, model: model, year: year, color: "Black", nickname: "N/A", gasLevel: 1.0)}
}var c = Car(make: "Ford", model: "Fusion", year: 2013)extension Car {enum Kind {case coupe, sedan}var kind: Kind {if numberOfDoors == 2 {return .coupe} else {return .sedan}}
}
c.kindextension Car {mutating func emptyGas(by amount: Double) {precondition(amount <= 1 && amount > 0, "Amount to remove must be between 0 and 1.")gasLevel -= amount}mutating func fillGas() {gasLevel = 1.0}
}
c.emptyGas(by: 0.3)
c.gasLevel
c.fillGas()
c.gasLevel
(2)扩展协议
protocol Exercise: CustomStringConvertible {var name: String { get }var caloriesBurned: Double { get } //消耗的卡路里var minutes: Double { get }//锻炼的时长
}extension Exercise {var description: String {return "Exercise(\(name), burned \(caloriesBurned) calories in \(minutes) minutes)"}
}extension Exercise {var title: String {return "\(name) - \(minutes) minutes"}
}struct EllipticalWorkout: Exercise {let name: String = "Elliptical Workout"let title: String = "Workout using the Go Fast Elliptical Trainer 3000"let caloriesBurned: Doublelet minutes: Double
}struct TreadmillWorkout: Exercise {let name: String = "Treadmill Workout"let caloriesBurned: Doublelet minutes: Doublelet laps: Double //跑步的圈数
}
extension TreadmillWorkout {var description: String {return "TreadmillWorkout(\(caloriesBurned) calories and \(laps) laps in \(minutes) minutes)"}
}let ellipticalWorkout = EllipticalWorkout(caloriesBurned: 335, minutes: 30)
let runningWorkout = TreadmillWorkout(caloriesBurned: 350, minutes: 25, laps: 10.5)
//使用范型定义函数:计算每分钟消耗的卡路里
func caloriesBurnedPerMinute<E: Exercise>(for exercise: E) -> Double {return exercise.caloriesBurned / exercise.minutes
}
print(caloriesBurnedPerMinute(for: ellipticalWorkout))
print(caloriesBurnedPerMinute(for: runningWorkout))//拓展协议
extension Exercise {//所有实现该协议的类型都可以使用通过拓展为该协议添加的属性和方法var caloriesBurnedPerMinute: Double {return caloriesBurned / minutes}
}print(ellipticalWorkout.caloriesBurnedPerMinute)
print(runningWorkout.caloriesBurnedPerMinute)
print(ellipticalWorkout)
print(runningWorkout)//带 where 子句的协议拓展
extension Sequence where Iterator.Element == Exercise {func totalCaloriesBurned() -> Double {var total: Double = 0for exercise in self {total += exercise.caloriesBurned}return total}
}let mondayWorkout: [Exercise] = [ellipticalWorkout, runningWorkout]
print(mondayWorkout.totalCaloriesBurned())for exercise in mondayWorkout {print(exercise.title)
}
print(ellipticalWorkout.title)
5、范型
struct StackIterator<T>: IteratorProtocol {
// typealias Element = Tvar stack: Stack<T>mutating func next() -> T? {return stack.pop()}
}// Sequence 是实现 for-in 循环在内部使用的协议
struct Stack<E>: Sequence {var items = [E]()// 使用 where 子句约束 Sequence 的元素类型mutating func pushAll<S: Sequence>(_ sequence: S) where S.Iterator.Element == E {for item in sequence {self.push(item)}}mutating func push(_ newItem: E) {items.append(newItem)}mutating func pop() -> E? {guard !items.isEmpty else {return nil}return items.removeLast()}func map<U>(_ f: (E) -> U) -> Stack<U> {var mappedItems = [U]()for item in items {mappedItems.append(f(item))}return Stack<U>(items: mappedItems)}func makeIterator() -> StackIterator<E> {return StackIterator(stack: self)}
}var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
var doubledStack = intStack.map { 2 * $0 }print(intStack.pop())
print(intStack.pop())
print(intStack.pop())
print(doubledStack.pop())
print(doubledStack.pop())func myMap<T, U>(_ items: [T], _ f: (T) -> U) -> [U] {var result = [U]()for item in items {result.append(f(item))}return result
}
let strings = ["one", "two", "three"]
//let stringLengths = myMap(strings, {(str: String) -> Int in
// return str.count
//})
let stringLengths = myMap(strings) { $0.count }
print(stringLengths)//类型约束
func checkIfEqual<T: Equatable>(_ first: T, _ second: T) -> Bool {return first == second
}
print(checkIfEqual(1, 1))
print(checkIfEqual("a string", "a string"))
print(checkIfEqual("a string", "a different string"))//每个占位类型都可以有一个类型约束
func checkIfDescriptionsMatch<T: CustomStringConvertible, U: CustomStringConvertible>(_ first: T, _ second: U) -> Bool {return first.description == second.description
}print(checkIfDescriptionsMatch(Int(1), UInt(1)))
print(checkIfDescriptionsMatch(1, 1.0))
print(checkIfDescriptionsMatch(Float(1.0), Double(1.0)))var myStack = Stack<Int>()
myStack.push(10)
myStack.push(20)
myStack.push(30)
var myStackIterator = StackIterator(stack: myStack)
while let value = myStackIterator.next() {print("got \(value)")
}for value in myStack {print("for-in loop: got \(value)")
}
myStack.pushAll([1, 2, 3])
for value in myStack {print("after pushing: got \(value)")
}
var myOtherStack = Stack<Int>()
myOtherStack.pushAll([1, 2, 3])
myStack.pushAll(myOtherStack)
for value in myStack {print("after pushing item onto stack, got \(value)")
}
6、协议
protocol TabularDataSource {var numberOfRows: Int { get }var numberOfColumns: Int { get }func label(forColumn column: Int) -> Stringfunc itemFor(row: Int, column: Int) -> String
}protocol PrintableTabularDataSource: TabularDataSource, CustomStringConvertible {//
}//组合协议,让 printTable 的参数符合 CustomStringConvertible 协议
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {print(dataSource)var firstRow = "|"var columnWidths = [Int]()for i in 0..<dataSource.numberOfColumns {let columnLabel = dataSource.label(forColumn: i)let columnHeader = " \(columnLabel) |"firstRow += columnHeadercolumnWidths.append(columnLabel.count)}print(firstRow)for i in 0..<dataSource.numberOfRows {var out = "|"for j in 0..<dataSource.numberOfColumns {let item = dataSource.itemFor(row: i, column: j)let paddingNeeded = columnWidths[j] - item.countlet padding = repeatElement(" ", count: paddingNeeded).joined(separator: "")out += " \(padding)\(item) |"}print(out)}
}struct Person {let name: Stringlet age: Intlet yearsOfExperience: Int
}struct Department: TabularDataSource, CustomStringConvertible {let name: Stringvar people = [Person]()var description: String {return "Department (\(name))"}init(name: String) {self.name = name}mutating func add(_ person: Person) {people.append(person)}var numberOfRows: Int {return people.count}var numberOfColumns: Int {return 3}func label(forColumn column: Int) -> String {switch column {case 0: return "Employee Name"case 1: return "Age"case 2: return "Years of Experience"default: fatalError("Invalid column!")}}func itemFor(row: Int, column: Int) -> String {let person = people[row]switch column {case 0: return person.namecase 1: return String(person.age)case 2: return String(person.yearsOfExperience)default: fatalError("Invalid column!")}}
}var department = Department(name: "Engineering")
department.add(Person(name: "Joe", age: 30, yearsOfExperience: 6))
department.add(Person(name: "Karen", age: 40, yearsOfExperience: 18))
department.add(Person(name: "Fred", age: 50, yearsOfExperience: 20))printTable(department)
7、字符串
import Cocoaextension String {/// 截取字符串/// - Parameter start: 起始索引(包含)/// - Parameter end: 结束索引(不包含)func substring(start: Int, end: Int) -> String {let firstIndex = index(startIndex, offsetBy: start)let lastIndex = index(startIndex, offsetBy: end)return String(self[firstIndex..<lastIndex])}/// 16进制字符串(可以有空格)转换成二进制数据func toData() -> Data {let hex = self.replacingOccurrences(of: " ", with: "")var arr = Array<UInt8>()for i in 0..<hex.count where i % 2 == 0 {let byteStr = hex.substring(start: i, end: i + 2)// print("byteStr = \(byteStr)")arr.append(UInt8(byteStr, radix: 16) ?? 0)}return Data(arr)}
}extension Data {/// 按照 ASCII 转换成字符串func toAscii() -> String {return subdata2ascii(start: 0, end: self.count)}/// 转换成16进制字符串/// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格func toHex(withSpace: Bool = true) -> String {return subdata2hex(start: 0, end: self.count, withSpace: withSpace)}/// 将指定范围的数据转换成ASCII字符串/// - Parameter start: 起始索引(包含)/// - Parameter end: 结束索引(不包含)func subdata2ascii(start: Int, end: Int) -> String {if let str = String(data: self[start..<end], encoding: .ascii) {return str}return ""}/// 将指定范围的数据转换成16进制字符串/// - Parameter start: 起始索引(包含)/// - Parameter end: 结束索引(不包含)/// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格func subdata2hex(start: Int, end: Int, withSpace: Bool = true) -> String {let arr = Array<UInt8>(self[start..<end])let hex = arr.map({ byte -> String inreturn String(format: "%02X", byte)}).joined(separator: withSpace ? " " : "")return hex}
}func test() {let hexString = "5A 58 48 0C 83 0E 47 07 22 2B 42 41 30 34 56 30 35"let data = hexString.toData()print("head = \(data.subdata2ascii(start: 0, end: 3))")print("mac = \(data.subdata2hex(start: 3, end: 9))")print("DeviceType = \(data.subdata2ascii(start: 9, end: 14))")print("version = \(data.subdata2ascii(start: 14, end: data.count))")print(data.toHex(withSpace: true))
}test()let apples = 3
let oranges = 5
//只要与结束引号(""")的缩进匹配,就会删除每一行开始处的缩进
let quotation = """Even though there's whitespace to the left,the actual lines aren't indented.Except for this line.Double quotes (") can appear without being escaped.I still have \(apples + oranges) pieces of fruit."""
print(quotation)
8、类和结构体
/** struct 类似 Kotlin 的 data class,等价写法是:data class Person(var firstName: String = "Matt", var lastName: String = "Mathias")*/
struct Person {var firstName = "Matt"var lastName = "Mathias"
}var p = Person(firstName: "Jia", lastName: "Jiefei")
print(p)//如果属性没有提供默认值,结构体会根据属性生成默认的成员初始化方法,并且直接打印结构体可以看到所有存储属性的值
struct Device {var name: Stringvar address: String// text 是计算属性,打印时不会输出var text: String {return "name=\(name), address=\(address)"}
}
print(Device(name: "Device", address: "11:22:33:44:55:66"))//而类就没有默认成员初始化方法了,需要自己编写初始化方法,并且直接打印类实例,不会输出各存储属性的值
class BleDevice {var name: Stringvar address: Stringrequired init(name: String, address: String) {self.name = nameself.address = address}
}
print(BleDevice(name: "BleDevice", address: "AA:BB:CC:DD:EE:FF"))
9、值类型和引用类型
//类是引用类型
class GreekGod {var name: Stringinit(name: String) {self.name = name}
}let hecate = GreekGod(name: "Hecate")
let athena = GreekGod(name: "Athena")
let zeus = GreekGod(name: "Zeus")
let anotherHecate = hecate
anotherHecate.name = "AnotherHecate"
hecate.name //类是引用类型,改变 anotherHecate.name,hecate.name也会变//结构体是值类型
struct Pantheon {var chiefGod: GreekGod
}let pantheon = Pantheon(chiefGod: hecate)pantheon.chiefGod.name // AnotherHecate
let greekPantheon = pantheon
hecate.name = "Trivia"
greekPantheon.chiefGod.name // Trivialet gods = [athena, hecate, zeus]
let godsCopy = gods
gods.last?.name = "Jupiter"
godsCopy.last?.name // Jupiter//探究写时复制(copy on write, COW)
fileprivate class IntArrayBuffer {var storage: [Int]init() {storage = []}init(buffer: IntArrayBuffer) {storage = buffer.storage}
}struct IntArray {private var buffer: IntArrayBufferinit() {buffer = IntArrayBuffer()}func describe() {let str = buffer.storage.map { i inString(i)}.joined(separator: ", ")print("[\(str)]")
// print(buffer.storage)}private mutating func copyIfNeeded() {//判断引用类型是否只有一个引用if !isKnownUniquelyReferenced(&buffer) {print("Making a copy of \(buffer.storage)")buffer = IntArrayBuffer(buffer: buffer)}}mutating func insert(_ value: Int, at index: Int) {copyIfNeeded()buffer.storage.insert(value, at: index)}mutating func append(_ value: Int) {copyIfNeeded()buffer.storage.append(value)}mutating func remove(at index: Int) {copyIfNeeded()buffer.storage.remove(at: index)}
}var integers = IntArray()
integers.append(1)
integers.append(2)
integers.append(4)
integers.describe()
var ints = integers
ints.insert(3, at: 2)
integers.describe()
ints.describe()
10、继承
虽然是讲继承,但代码中的注释也会涉及其他知识点!例子涉及3个.swift文件
Town.swift
struct Town {let region: Stringvar population: Int {didSet {print("The population has changed to \(population) from \(oldValue)")}}var numberOfStoplights: Int//自定义初始化方法,问号表示可失败的初始化方法init?(region: String, population: Int, stoplights: Int) {guard population > 0 else {return nil}self.region = regionself.population = populationnumberOfStoplights = stoplights}//委托初始化init?(population: Int, stoplights: Int) {self.init(region: "N/A", population: population, stoplights: stoplights)}enum Size {case smallcase mediumcase large}//计算属性var townSize: Size {get {print("town size")//每次调用都会打印switch self.population {case 0...10_000:return Size.smallcase 10_001...100_000:return Size.mediumdefault:return Size.large}}}//惰性存储属性,注意这里的等号以及结尾的圆括号lazy var name: String = {print("town name")//这里只会打印一次,即第一次访问该属性时return "XiShe"}()func printDescription() {print("Population: \(population), number of stoplights: \(numberOfStoplights), region: \(region)")}/* 如果结构体(确切的说,应该是值类型,结构体和枚举都是值类型)的一个实例方法需要修改结构体的属性,就必须使用 mutating 标记该方法 */mutating func changePopulation(by amount: Int) {population += amount}/* 对于值类型,类型方法使用static标记 */static func xxx() {}
}
Monster.swift
class Monster {// static 属性无法被子类覆盖static let isTerrifying = true// class 属性可被子类覆盖class var spookyNoise: String {return "Grrr"}var town: Town?var name: Stringvar victimPool: Int {get {return town?.population ?? 0}set {town?.population = newValue}}//子类必须得实现的初始化方法required init(town: Town?, monsterName: String) {self.town = townname = monsterName}func terrorizeTown() {if town != nil {print("\(name) is terrorizing a town!")} else {print("\(name) hasn't found a town to terrorize yet...")}}/* 对于类,类型方法使用class或者static标记,区别在于static标记的方法无法被子类重写,也可以使用final class代替static */static func makeSpookyNoise() {print("Brains...")}
}
Zombie.swift
class Zombie: Monster {override class var spookyNoise: String {return "Brains..."}var walkWithLimp: Bool//只将 set 属性设置为私有,get 属性为默认的 internalprivate(set) var isFallingApart: Bool//指定初始化方法init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {walkWithLimp = limpisFallingApart = fallingApart//如果有父类,子类的指定初始化方法必须调用父类的指定初始化方法super.init(town: town, monsterName: monsterName)}//便捷初始化方法,必须调用指定初始化方法或者其他便捷初始化方法,但最终都要调用指定初始化方法,以确保所有属性都进行了初始化convenience init(limp: Bool, fallingApart: Bool) {self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")if walkWithLimp {print("This zombie has a bad knee.")}}required init(town: Town?, monsterName: String) {walkWithLimp = falseisFallingApart = falsesuper.init(town: town, monsterName: monsterName)}//实例被清除出内存时会触发反初始化deinit {print("Zombie named \(name) is no longer with use.")}//final 禁止子类重写该方法final override func terrorizeTown() {if !isFallingApart {town?.changePopulation(by: -10)}super.terrorizeTown()}
}
测试代码
var town = Town(region: "West", population: 10, stoplights: 6)
town?.printDescription()
for _ in 0..<3 {if let townSize = town?.townSize, let townName = town?.name {print(townSize)print(townName)}town?.changePopulation(by: 1_000_000)
}
//let genericMonster = Monster()
//genericMonster.town = town
//genericMonster.terrorizeTown()
var fredTheZombie: Zombie? = Zombie(limp: false, fallingApart: false, town: town, monsterName: "Fred")
//fredTheZombie.terrorizeTown()
//fredTheZombie.town?.printDescription()
//Monster.makeSpookyNoise()
print("Victim pool: \(fredTheZombie?.victimPool)")
fredTheZombie?.victimPool = 500
fredTheZombie = nil
print(Monster.spookyNoise)
print(Zombie.spookyNoise)
11、数组和字典
//初始化数组的3种方式,本人习惯上倾向使用第一种
//使用 var 就是可变数组,let就是不可变数组
var bucketList: Array<String> = []
var bucketList2:[String] = ["haha"]
var arr = [Int]()
arr.append(1)
arr.append(3)
arr.append(2)
//print("bucketList.count=\(bucketList.count) arr[0]=\(arr[0])")
//数组排序
let sortedArray = arr.sorted(by: {a, b ina < b
})
print(sortedArray)
//注:只有Array<String> 才有 joined 方法,如果元素类型不是 String,得先通过 map 方法转一次
let joinedString = arr.map { i inString(i)
}.joined(separator: ", ")
print("[\(joinedString)]")//字典也有多种初始化方式,这里只列出其中一种
//使用 var 就是可变字典,let就是不可变字典
var dict: Dictionary<String, Int> = [:]
dict["one"] = 1
dict["two"] = 2
dict["three"] = 3
//遍历字典
for (key, value) in dict {print("\(key) = \(value)")
}
dict.removeValue(forKey: "one")
dict["two"] = nil //将值设置为nil来删除键值对
print(dict)
相关文章:
Swift基础
本文是个比较简单的学习笔记,更详细的内容见 Swift官方文档 1、相等性比较 Swift标准库用 < 和 运算符定义了 >、>、<,所以实现 Comparable 的 < 运算符就会自动得到这些运算符的实现,实际上 Comparable 继承自 Equatable&…...
基于php+thinkphp+vue的校园二手交易网站
运行环境 开发语言:PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发…...
SystemVerilog Assertions应用指南 第一章(1.25章节 “first_match”运算符)
任何时候使用了逻辑运算符(如“and”和“or”)的序列中指定了时间窗,就有可能出现同一个检验具有多个匹配的情况。“ first match”构造可以确保只用第一次序列匹配,而丢弃其他的匹配。当多个序列被组合在一起,其中只需时间窗内的第一次匹配来检验属性剩余的部分时,“ first ma…...
python和go执行字符串表达式
1、python/eval python里可以使用内置的eval函数,来执行一个字符串表达式的结果,字符串表达式里可以是变量、函数、运算符等 def test():return True flag False print(eval("test() and True and flag" )) 执行结果为False 2、golang/go…...
Python算法练习 10.14
leetcode 2095 删除链表的中间节点 给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。 长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于…...
云上攻防-云原生篇Docker安全系统内核版本漏洞CDK自动利用容器逃逸
文章目录 云原生-Docker安全-容器逃逸&内核漏洞云原生-Docker安全-容器逃逸&版本漏洞-CVE-2019-5736 runC容器逃逸-CVE-2020-15257 containerd逃逸 云原生-Docker安全-容器逃逸&CDK自动化 云原生-Docker安全-容器逃逸&内核漏洞 细节部分在权限提升章节会详解&…...
C# Sqlite数据库的搭建及使用技巧
C# Sqlite数据库的搭建 前言: 今天我们来学一下Sqlite的数据库的搭建,Sqlite数据库不比MySqL数据库,SQlite数据是一个比较轻量级的数据库,SQLite提供了比较多的工具集,对数据基本上不挑,什么数据都可以处理ÿ…...
gerrit代码review使用基本方法
1、repo拉取代码 repo init -u ssh://gerrit.senseauto.com/senseauto_manifest -b develop -m senseauto-config.xml --repo-urlssh://gerrit.senseauto.com:29418/senseauto_repo --repo-branchdevelop --no-repo-verify repo sync -j4 repo forall -j 4 -p -c ‘git lfs p…...
网络监控与故障排除:netstat命令的使用指南
文章目录 概述什么是 netstat 命令?netstat 命令的作用和功能netstat 命令的常见用途 安装和基本用法安装 netstat 命令netstat 命令的基本语法查看活动网络连接 查看网络接口信息查看所有网络接口信息查看指定网络接口信息网络接口状态说明 网络连接状态显示所有连…...
Blender:渲染一个简单动画
接上 Blender:对模型着色_六月的翅膀的博客-CSDN博客 目标是做一个这种视频 先添加一个曲线,作为相机轨迹 然后添加一个相机 对相机添加物体约束,跟随路径,选择曲线,然后点击动画路径 假如对相机设置跟随路径后&…...
一篇文章带你用动态规划解决股票购买时机问题
动态规划的解题步骤可以分为以下五步,大家先好好记住 1.创建dp数组以及明确dp数组下标的含义 2.制定递推公式 3.初始化 4.遍历顺序 5.验证结果 股票购买时机问题的解题核心思路 当天的收益是根据前一天持有股票还是不持有股票的状态决定的 那么很自然的我们就想…...
【设计模式】使用建造者模式组装对象并加入自定义校验
文章目录 1.前言1.1.创建对象时的痛点 2.建造者模式2.1 被建造类准备2.2.建造者类实现2.3.构建对象测试2.4.使用lombok简化建造者2.5.lombok简化建造者的缺陷 3.总结 1.前言 在我刚入行不久的时候就听说过建造者模式这种设计模式,当时只知道是用来组装对象…...
简单聊聊低代码
在数字经济迅速发展的背景下,越来越多的企业开始建立健全业务系统、应用、借助数字化工具提升管理效率,驱动业务发展,促进业绩增长。在这一过程中,和许多新技术一样,低代码(Low-code)开发被推上…...
SystemVerilog Assertions应用指南 第一章(1.27章节 “within”运算符)
“ within”构造允许在一个序列中定义另一个序列。 seq1 within seq2 这表示seq1在seq2的开始到结束的范围内发生,且序列seq2的开始匹配点必须在seq1的开始匹配点之前发生,序列seq1的结束匹配点必须在seq2的结束匹配点之前结束。属性p32检查序列s32a在信号“ start”的上升沿和…...
2023年09月 C/C++(七级)真题解析#中国电子学会#全国青少年软件编程等级考试
C/C++编程(1~8级)全部真题・点这里 Python编程(1~6级)全部真题・点这里 第1题:红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 时间限…...
[Mono Depth/3DOD]单目3D检测基础
1. 数据增强 图像放缩和裁剪后,相机内参要做相应变化 import random def random_scale(image, calib, scale_range(0.8, 1.2)):scale random.uniform(*scale_range)width, height image.sizeimage image.resize((int(width * scale), int(height * scale)))cal…...
【Docker 内核详解】namespace 资源隔离(三):PID namespace
namespace 资源隔离(三):PID namespace 1.PID namespace 中的 init 进程2.信号与 init 进程3.挂载 proc 文件系统4.unshare() 和 setns() PID namespace 隔离非常实用,它对进程 PID 重新标号,即两个不同 namespace 下的…...
1600*C. Game On Leaves(博弈游戏树)
Problem - 1363C - Codeforces 解析: 我们将目标结点 x 当作树的根,显然,到当 x 的度为 1 的时候,此时行动的人胜利。 我们假设现在的情况为,只剩余三个点,再选择任意一个点,则对方获胜。但是两…...
Apache Ant的安装
介绍 Apache Ant是一个Java库和一个 命令行工具,可以用来构建Java应用。Ant提供了许多内置的任务(tasks),可以编译、组装、测试、运行Java应用。Ant也可以构建非Java应用,例如C、C应用。 Ant非常灵活,没有…...
考研:数学二例题--∞−∞和0⋅∞型极限
前言 本文只是例题,建议先参考具体如何做这类型例题。请到主文章中参考:https://blog.csdn.net/grd_java/article/details/132246630 ∞ − ∞ 和 0 ⋅ ∞ \infin - \infin 和 0\infin ∞−∞和0⋅∞ 例题 例1: lim x → ∞ x 2 x 2 −…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
