Worked on Swift documentation
This commit is contained in:
parent
2bdf142d39
commit
f0bb94ebd5
717
swift/README.md
Normal file
717
swift/README.md
Normal file
@ -0,0 +1,717 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/swift/swift-original.svg" alt="Swift" width="250"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
- [General Notes](#general-notes)
|
||||||
|
- [Swift project](#swift-project)
|
||||||
|
- [Package.swift](#packageswift)
|
||||||
|
- [Foundation](#foundation)
|
||||||
|
- [Syntax](#syntax)
|
||||||
|
- [Functions, if-else, loops, etc.](#functions-if-else-loops-etc)
|
||||||
|
- [Var vs. let](#var-vs-let)
|
||||||
|
- [Language features](#language-features)
|
||||||
|
- [Pattern matching](#pattern-matching)
|
||||||
|
- [Classes](#classes)
|
||||||
|
- [Structs](#structs)
|
||||||
|
- [Enums](#enums)
|
||||||
|
- [OOP stuff](#oop-stuff)
|
||||||
|
- [POP (Protocol-Oriented Programming)](#pop-protocol-oriented-programming)
|
||||||
|
- [Functional stuffies](#functional-stuffies)
|
||||||
|
- [Scope and shizz](#scope-and-shizz)
|
||||||
|
- [Optionals](#optionals)
|
||||||
|
- [Closures](#closures)
|
||||||
|
- [Other stuff](#other-stuff)
|
||||||
|
- [Naming conventions](#naming-conventions)
|
||||||
|
- ["Main" function? `if __name__ == "__main__":`?](#main-function-if-__name__--__main__)
|
||||||
|
- [Docstrings](#docstrings)
|
||||||
|
- [Project-specific Notes](#project-specific-notes)
|
||||||
|
- [Most likely teammates for Software engineering](#most-likely-teammates-for-software-engineering)
|
||||||
|
|
||||||
|
# General Notes
|
||||||
|
There are **NO** semicolons in Swift. The language is designed to be concise and readable. Very pythonic in that sense.
|
||||||
|
|
||||||
|
Swift is a statically-typed language. This means that the type of a variable is known at compile time. This is in contrast to dynamically-typed languages like Python, where the type of a variable is determined at runtime.
|
||||||
|
|
||||||
|
Swift deals with memory by using Automatic Reference Counting (ARC). This means that the compiler automatically manages memory for you. This is in contrast to languages like C and C++, where you have to manually manage memory.
|
||||||
|
|
||||||
|
Swift is a multi-paradigm language. This means that it supports multiple programming paradigms, such as object-oriented programming, functional programming, and procedural programming. We'll get into this later.
|
||||||
|
|
||||||
|
|
||||||
|
## Swift project
|
||||||
|
|
||||||
|
Creating a new project:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
swift package init --type executable
|
||||||
|
```
|
||||||
|
`--type` flag specifies the type of the project. In this case, it is an executable. Other options include `library` and `system-module`.
|
||||||
|
|
||||||
|
Running the project (this will build and run the project):
|
||||||
|
```bash
|
||||||
|
swift run
|
||||||
|
```
|
||||||
|
|
||||||
|
Building the project:
|
||||||
|
```bash
|
||||||
|
swift build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a `.build` directory in the root of the project. The executable will be in `.build/debug/` directory (default filename is `swift`).
|
||||||
|
|
||||||
|
|
||||||
|
### Package.swift
|
||||||
|
This file is the equivalent of `requirements.txt` in Python. It specifies the dependencies of the project.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
```swift
|
||||||
|
// swift-tools-version: 6.0
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "swift",
|
||||||
|
targets: [
|
||||||
|
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||||
|
// Targets can depend on other targets in this package and products from dependencies.
|
||||||
|
.executableTarget(
|
||||||
|
name: "swift"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
To add a dependency, add the following to the `Package.swift` file:
|
||||||
|
```swift
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "
|
||||||
|
https://whatever.com", from: "1.0.0")
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
To import the dependency in the code:
|
||||||
|
```swift
|
||||||
|
import Whatever
|
||||||
|
```
|
||||||
|
|
||||||
|
To update the dependencies:
|
||||||
|
```bash
|
||||||
|
swift package update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Foundation
|
||||||
|
|
||||||
|
Foundation is a library that provides basic functionality for Swift. It is similar to the `stdlib` in C.
|
||||||
|
|
||||||
|
To import Foundation:
|
||||||
|
```swift
|
||||||
|
import Foundation
|
||||||
|
```
|
||||||
|
|
||||||
|
To use a function from Foundation:
|
||||||
|
```swift
|
||||||
|
let date = Date()
|
||||||
|
```
|
||||||
|
|
||||||
|
To use a class from Foundation:
|
||||||
|
```swift
|
||||||
|
let url = URL(string: "https://www.google.com")
|
||||||
|
```
|
||||||
|
|
||||||
|
Etc. etc.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// This is a comment
|
||||||
|
```
|
||||||
|
|
||||||
|
Variables are declared as follows:
|
||||||
|
```swift
|
||||||
|
var x = 5
|
||||||
|
let y = 10
|
||||||
|
```
|
||||||
|
|
||||||
|
Types are inferred by the compiler. However, you can specify the type explicitly:
|
||||||
|
```swift
|
||||||
|
var x: Int = 5
|
||||||
|
let y: Double = 10.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Strings are declared as follows:
|
||||||
|
```swift
|
||||||
|
let str = "Hello, world!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Arrays are declared as follows:
|
||||||
|
```swift
|
||||||
|
let arr = [1, 2, 3, 4, 5]
|
||||||
|
```
|
||||||
|
|
||||||
|
Dictionaries are declared as follows:
|
||||||
|
```swift
|
||||||
|
let dict = ["key1": "value1", "key2": "value2"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Tuples are declared as follows:
|
||||||
|
```swift
|
||||||
|
let tuple = (1, "hello", 3.14)
|
||||||
|
```
|
||||||
|
|
||||||
|
To access elements of a tuple (unpacking):
|
||||||
|
```swift
|
||||||
|
let (a, b, c) = tuple
|
||||||
|
print(a) // 1
|
||||||
|
print(b) // hello
|
||||||
|
print(c) // 3.14
|
||||||
|
```
|
||||||
|
|
||||||
|
To access elements of an array:
|
||||||
|
```swift
|
||||||
|
print(arr[0]) // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
To access elements of a dictionary:
|
||||||
|
```swift
|
||||||
|
print(dict["key1"]) // value1
|
||||||
|
```
|
||||||
|
|
||||||
|
To access the length of an array:
|
||||||
|
```swift
|
||||||
|
print(arr.count)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Functions, if-else, loops, etc.
|
||||||
|
|
||||||
|
Functions are defined as follows:
|
||||||
|
```swift
|
||||||
|
func functionName(arg1: Type, arg2: Type) -> ReturnType {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> In Swift, the underscore (`_`) in function parameters signifies that the parameter name is omitted when calling the function. It essentially means "ignore the external name for this parameter," similar to the `*args` and `**kwargs` in Python.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For loops:
|
||||||
|
```swift
|
||||||
|
for i in 0..<10 { // Note that 0..<10 is a range, equivalent to range(10) in Python
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
While loops:
|
||||||
|
```swift
|
||||||
|
while condition {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Repeat-while loops (do-while in other languages):
|
||||||
|
```swift
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
// code
|
||||||
|
} while condition
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If-else statements:
|
||||||
|
```swift
|
||||||
|
if condition {
|
||||||
|
// code
|
||||||
|
} else if condition {
|
||||||
|
// code
|
||||||
|
} else {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Switch statements:
|
||||||
|
```swift
|
||||||
|
switch value {
|
||||||
|
case 1:
|
||||||
|
// code
|
||||||
|
case 2:
|
||||||
|
// code
|
||||||
|
default:
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**A guard statement** is used to transfer program control out of a scope if one or more conditions aren't met. It is similar to an if-else statement, but it is used to exit early if a condition is not met.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
guard condition else {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Actual example:
|
||||||
|
```swift
|
||||||
|
guard let url = URL(string: "https://www.google.com") else {
|
||||||
|
print("Invalid URL")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In python, this would be:
|
||||||
|
```python
|
||||||
|
if not url := URL("https://www.google.com"):
|
||||||
|
print("Invalid URL")
|
||||||
|
return
|
||||||
|
```
|
||||||
|
|
||||||
|
A guard statement is used to make the code more readable and to avoid the pyramid of doom.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
Try catch statements:
|
||||||
|
```swift
|
||||||
|
do {
|
||||||
|
try someFunction()
|
||||||
|
} catch {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Throwing an error:
|
||||||
|
```swift
|
||||||
|
func someFunction() throws { // Java-esque throws keyword
|
||||||
|
if condition {
|
||||||
|
throw SomeError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A defer statement is used to execute a block of code just before the function returns. It is similar to the `finally` block in Python (outside of the context of exceptions).
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func someFunction() {
|
||||||
|
defer {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Defer statements are executed in reverse order, i.e., the last defer statement is executed first.
|
||||||
|
|
||||||
|
Practical example:
|
||||||
|
```swift
|
||||||
|
func openFile() {
|
||||||
|
let file = open("file.txt")
|
||||||
|
defer {
|
||||||
|
close(file)
|
||||||
|
}
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Var vs. let
|
||||||
|
|
||||||
|
`var` is used to declare a variable. It is mutable.
|
||||||
|
|
||||||
|
`let` is used to declare a constant. It is immutable.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var x = 5
|
||||||
|
x = 6 // valid
|
||||||
|
|
||||||
|
let y = 5
|
||||||
|
y = 6 // invalid
|
||||||
|
```
|
||||||
|
|
||||||
|
We love memory safety <3. This is exactly the same as `const` in JavaScript.
|
||||||
|
On a sidenote, what is the difference between `let` and `var` in JavaScript? `let` is block-scoped, while `var` is function-scoped. Good segue to-
|
||||||
|
|
||||||
|
## Language features
|
||||||
|
|
||||||
|
|
||||||
|
### Pattern matching
|
||||||
|
OH YES! Pattern matching is a powerful feature in Swift. It is used to match values against patterns. The Python equivalent would probably be `in` or the `re` module.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let numbers = [10, 15, 20, 25, 30]
|
||||||
|
|
||||||
|
for num in numbers where num % 10 == 0 {
|
||||||
|
print(num) // 10, 20, 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Classes
|
||||||
|
|
||||||
|
Classes and structs are used to define custom data types.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
class Person {
|
||||||
|
var name: String
|
||||||
|
var age: Int
|
||||||
|
|
||||||
|
init(name: String, age: Int) {
|
||||||
|
self.name = name
|
||||||
|
self.age = age
|
||||||
|
}
|
||||||
|
|
||||||
|
func sayHello() {
|
||||||
|
print("Hello, my name is \(name)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let person = Person(name: "Alice", age: 25)
|
||||||
|
person.sayHello()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Structs
|
||||||
|
Structs are similar to classes, but they are value types. This means that when you pass a struct to
|
||||||
|
a function, a copy of the struct is passed, not a reference to the struct.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
struct Point {
|
||||||
|
var x: Int
|
||||||
|
var y: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
var point1 = Point(x: 1, y: 2)
|
||||||
|
var point2 = point1
|
||||||
|
point2.x = 3
|
||||||
|
print(point1.x) // 1
|
||||||
|
print(point2.x) // 3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enums
|
||||||
|
|
||||||
|
Enums are used to define a group of related values. They are similar to enums in C and Java.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
enum Direction {
|
||||||
|
case north
|
||||||
|
case south
|
||||||
|
case east
|
||||||
|
case west
|
||||||
|
}
|
||||||
|
|
||||||
|
let direction = Direction.north
|
||||||
|
|
||||||
|
// We also got associated values (which means that each case can have a value associated with it)
|
||||||
|
enum Result {
|
||||||
|
case success(Int)
|
||||||
|
case failure(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = Result.success(42)
|
||||||
|
let result2 = Result.success("Error") // invalid
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### OOP stuff
|
||||||
|
|
||||||
|
Inheritance is done using the `:` operator.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
class Animal {
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
init(name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSound() {
|
||||||
|
print("Animal sound")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog: Animal {
|
||||||
|
override func makeSound() { // Method overriding, similar to Java
|
||||||
|
print("Woof")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dog = Dog(name: "Rex")
|
||||||
|
dog.makeSound()
|
||||||
|
```
|
||||||
|
|
||||||
|
Extensions are used to add new functionality to existing classes, structs, and *protocols*. This is a way better way to do this than reflection in Java. Safe and concise.
|
||||||
|
|
||||||
|
|
||||||
|
```swift
|
||||||
|
extension Int {
|
||||||
|
func squared() -> Int {
|
||||||
|
return self * self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = 5
|
||||||
|
print(x.squared()) // 25
|
||||||
|
```
|
||||||
|
|
||||||
|
### POP (Protocol-Oriented Programming)
|
||||||
|
What's this? It's a paradigm that combines the best of OOP and functional
|
||||||
|
programming. It is similar to interfaces in Java.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
protocol Animal {
|
||||||
|
var name: String { get set } // Getters and setters (Lombok - @Data)
|
||||||
|
func makeSound()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog: Animal {
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
init(name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSound() {
|
||||||
|
print("Woof")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The reason why POP is so powerful is that it allows you to define default implementations for methods in protocols. This is similar to abstract classes in Java.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
protocol Animal {
|
||||||
|
var name: String { get set }
|
||||||
|
func makeSound()
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Animal {
|
||||||
|
func makeSound() {
|
||||||
|
print("Animal sound")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog: Animal {
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
init(name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dog = Dog(name: "Rex")
|
||||||
|
dog.makeSound() // Animal sound
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Functional stuffies
|
||||||
|
|
||||||
|
Swift has a couple of higher-order functions that are similar to Python/Haskell.
|
||||||
|
|
||||||
|
`map` is used to apply a function to each element of an array.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let arr = [1, 2, 3, 4, 5]
|
||||||
|
let newArr = arr.map { $0 * 2 } // $0 is the current element, equv to lambda in Python
|
||||||
|
print(newArr) // [2, 4, 6, 8, 10]
|
||||||
|
```
|
||||||
|
|
||||||
|
`filter` is used to filter elements of an array based on a condition.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let arr = [1, 2, 3, 4, 5]
|
||||||
|
let newArr = arr.filter { $0 % 2 == 0 }
|
||||||
|
print(newArr) // [2, 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
`reduce` is used to combine all elements of an array into a single value.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let arr = [1, 2, 3, 4, 5]
|
||||||
|
let sum = arr.reduce(0) { $0 + $1 }
|
||||||
|
print(sum) // 15
|
||||||
|
```
|
||||||
|
|
||||||
|
`sorted` is used to sort an array.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let arr = [5, 3, 1, 4, 2]
|
||||||
|
let sortedArr = arr.sorted()
|
||||||
|
|
||||||
|
print(sortedArr) // [1, 2, 3, 4, 5]
|
||||||
|
```
|
||||||
|
|
||||||
|
`forEach` is used to iterate over an array.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
|
||||||
|
let arr = [1, 2, 3, 4, 5]
|
||||||
|
arr.forEach { print($0) }
|
||||||
|
```
|
||||||
|
|
||||||
|
`compactMap` is used to remove `nil` values from an array.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let arr = [1, nil, 2, nil, 3, nil]
|
||||||
|
let newArr = arr.compactMap { $0 }
|
||||||
|
print(newArr) // [1, 2, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
[And so on and so forth.](https://www.appcoda.com/higher-order-functions-swift/)
|
||||||
|
|
||||||
|
### Scope and shizz
|
||||||
|
|
||||||
|
Swift has block scoping. Variables declared inside a block are not accessible outside of it.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
if true {
|
||||||
|
let a = 10
|
||||||
|
var b = 20
|
||||||
|
print(a) // valid
|
||||||
|
print(b) // valid
|
||||||
|
}
|
||||||
|
|
||||||
|
// print(a) // invalid, a is out of scope
|
||||||
|
// print(b) // invalid, b is out of scope
|
||||||
|
```
|
||||||
|
|
||||||
|
Function scope vs. global scope:
|
||||||
|
```swift
|
||||||
|
func doSomething() {
|
||||||
|
let localVar = 42
|
||||||
|
print(localVar) // valid
|
||||||
|
}
|
||||||
|
|
||||||
|
// print(localVar) // invalid, localVar is out of scope
|
||||||
|
```
|
||||||
|
|
||||||
|
Global variables are declared outside of any function or block. They are accessible from anywhere in the program.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let globalVar = 42
|
||||||
|
|
||||||
|
func doSomething() {
|
||||||
|
print(globalVar) // valid
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Shadowing[^1] is allowed.
|
||||||
|
|
||||||
|
### Optionals
|
||||||
|
|
||||||
|
Memory safety is a big deal in Swift. Optionals are used to handle the absence of a value. An optional is a type that can hold either a value or `nil`.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var optionalInt: Int? = 5
|
||||||
|
optionalInt = nil
|
||||||
|
```
|
||||||
|
|
||||||
|
The question mark `?` is used to denote an optional type. The `!` is used to force unwrap an optional. This is dangerous because if the optional is `nil`, the program will crash.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var optionalInt: Int? = 5
|
||||||
|
print(optionalInt!) // prints 5
|
||||||
|
optionalInt = nil
|
||||||
|
print(optionalInt!) // crashes
|
||||||
|
```
|
||||||
|
|
||||||
|
To safely unwrap an optional, use an if-let statement:
|
||||||
|
```swift
|
||||||
|
var optionalInt: Int? = 5
|
||||||
|
if let unwrappedInt = optionalInt {
|
||||||
|
print(unwrappedInt)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional chaining is used to access properties and methods of an optional that might be `nil`. If the optional is `nil`, the chain will short-circuit and return `nil`.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var str: String? = "Hello, world!"
|
||||||
|
let count = str?.count
|
||||||
|
```
|
||||||
|
|
||||||
|
Nil coalescing operator `??` is used to provide a default value for an optional if it is `nil`. It's like a `get` method in Python.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var optionalInt: Int? = nil
|
||||||
|
let unwrappedInt = optionalInt ?? 0
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Closures
|
||||||
|
|
||||||
|
Closures are self-contained blocks of code that can be passed around and used in your code. They are similar to lambda functions in Python.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let closure = {
|
||||||
|
print("Hello, world!")
|
||||||
|
}
|
||||||
|
|
||||||
|
closure()
|
||||||
|
```
|
||||||
|
|
||||||
|
Aint that nifty?
|
||||||
|
|
||||||
|
## Other stuff
|
||||||
|
|
||||||
|
### Naming conventions
|
||||||
|
|
||||||
|
- Use camelCase for variable names.
|
||||||
|
- Use PascalCase for type names.
|
||||||
|
- Use snake_case for function names.
|
||||||
|
- `_` is used as a wildcard in Swift. It is similar to the `_` in Python/Haskell.
|
||||||
|
|
||||||
|
### "Main" function? `if __name__ == "__main__":`?
|
||||||
|
|
||||||
|
In Swift, the entry point of a program is the `main.swift` file.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
print("Hello, world!")
|
||||||
|
```
|
||||||
|
|
||||||
|
There is no `main` function. Swift is smart enough to figure out that this is the entry point of the program.
|
||||||
|
|
||||||
|
IF you'd like to EXPLICITLY define the entry point, you can do so by annotating the file with `@main`.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
@main
|
||||||
|
struct MyProgram {
|
||||||
|
static func main() {
|
||||||
|
print("Hello, world!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the `struct` keyword. This is because `@main` is an attribute that can only be applied to a struct or a class.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The `@main` attribute is only applicable to **libraries**, if you are creating an executable, you don't need to use it.
|
||||||
|
|
||||||
|
|
||||||
|
### Docstrings
|
||||||
|
|
||||||
|
Docstrings are used to document functions, classes, and modules. They are enclosed in triple quotes.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
/**
|
||||||
|
This is a docstring.
|
||||||
|
*/
|
||||||
|
func someFunction() {
|
||||||
|
// code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Project-specific Notes
|
||||||
|
|
||||||
|
## [Most likely teammates for Software engineering](practical/01_mostLikelyTeams/README.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Footnotes -->
|
||||||
|
[^1]: Shadowing is the practice of using the same name for a variable in an inner scope as in an outer scope. The inner variable "shadows" the outer variable. This is useful when you want to use the same name for a variable in different scopes. However, it can lead to confusion and bugs if not used carefully.
|
Loading…
x
Reference in New Issue
Block a user