23. Expert #1
Operators
Short-circuit Evaluation, Side Effect
論理演算子が論理式を評価する方法を学習する
//flase &&
//true ||
// 달락 평가
var a = 1
var b = 1
func updateLeft() -> Bool {
a += 1
return false
}
func updateRight() -> Bool {
b += 1
return true
}
let resultA = updateLeft()
let resultB = updateRight()
if resultA && resultB {
}
a
b
Operator Methods
新しいフォーマットをサポートするために既存の演算子を拡張する方法を学習します.
static func operator(parameters) -> ReturnType {
statements
}
// 연산자 메소드
"a" == "a"
struct Point {
var x = 0.0
var y = 0.0
}
// 개별 속성 비교
extension Point: Equatable {
static func == (lhs: Point, rhs: Point) -> Bool {
return (lhs.x == rhs.x) && (lhs.y == rhs.y)
}
}
let p1 = Point(x: 12, y: 34)
let p2 = Point(x: 67, y: 89)
p1 == p2
p1 != p2
// prefix 키워드로 선언하면 피연산자 앞에 오는 전치연산자로 선언된다
extension Point {
static prefix func -(pt: Point) -> Point {
return Point(x: -pt.x, y: -pt.y)
}
}
let p3 = -p1
p3.x
p3.y
// 증감연산자
// postfix 키워드를 사용하면 피연산자 뒤에오는 후치 연산자로 사용됨
// 후치 증가 연산자 = 현재 값을 리턴한 다음 현재 값을 1씩 증가 시킨다
extension Point {
static postfix func ++(pt: inout Point) -> Point {
let ret = pt
pt.x += 1
pt.y += 1
return ret
}
}
var p4 = Point(x: 1.0, y: 2.0)
let p5 = p4++
p5.x
p5.y
p4.x
p4.y
Custom Operators
SWIFTで提供されていない新しい演算子を直接実装する方法を学習します.
prefix operator operator
postfix operator operator
infix operator operator
Reserved Tokens
(, ), {, }, [, ], .,, :, ;, =, @, #, &(prefix operator), ->, `, ?, !(postfix operator),/,/
First Character
/, =, -, +, !, *, %, <, >, &, |, ^, ?, ~
static prefix func operator(parameters) -> ReturnType {
statements
}
static postfix func operator(parameters) -> ReturnType {
statements
}
static func operator(parameters) -> ReturnType {
statements
}
Conditional Statements
Value Binding Pattern
switch文で使用できるValue Binding Patternについて
case let name:
case var name:
bellクラスバインドモードは、一致するターゲットを定数または変数にバインドし、キャビネットブロックで使用します.let a = 1
switch a {
case var x where x > 100: // case의 값을 바꾸려면 상수가 아니라 변수로 지정해야된다.
x = 200
print(x)
default:
break
}
// 벨류 바인딩은 튜플에서도 자주 사용
let pt = (1, 2)
switch pt {
case let(x, y): // 상수로 바인딩 할 때 이 코드가 간단
print(x, y)
case (let x, let y):
print(x,y)
case (let x, var y): // 상수로 바인딩하고 변수로 바인딩 할 때 활용
print(x,y)
case let(x, _): // 첫 번째 값만 바인딩(와일드 패턴을 활용)
print(x)
}
Expression Pattern
直接実装されたフォーマットにパターンマッチングを適用する方法を学習します.
let a = 1
switch a {
case 0...10:
print("0 ~ 10")
default:
break
}
Pattern Matching Operator
a ~= b
struct Size {
var width = 0.0
var height = 0.0
static func ~=(left: Range<Int>, right: Size) -> Bool {
return left.contains(Int(right.width))
// 첫 번째 파라미터로 전달 된 범위에 두 번째 파라미터로 전달 된 사이즈에 width의 값이 포함되어 있다면 True가 리턴
}
}
let s = Size(width: 5, height: 20)
switch s {
case 1..<9:
print("1 ~ 9")
case 10..<99:
print("10 ~ 99")
default:
break
}
Optionals
Optional Chaining
1つの式で複数の外部フォーマット・メンバーにアクセスする方法を学習します.
記憶.
1.トーナメントの結果はいつもトーナメント
2.オフセットフィルタの式で、nilを返す式がある場合は、直後の式ではなくnilを返します.
var p = Person(name: "Ben", email: "[email protected]")
let a = p.contacts?.address
var optionalP: Person? = Person(name: "Ben", email: "[email protected]")
let b = optionalP?.contacts?.address
b
optionalP = nil
let c = optionalP?.contacts?.address
c
p.contacts?.address?.count
p.getContacts()?.address
// let f: (() -> Contacts?)? = p.getContacts
// 함수나 메서드에 옵셔널 값이 접근할 떄는 괄호 뒤에 ?를 붙인다.
// f?()?.address
let d = p.getContacts()?.printAddress()
if p.getContacts()?.printAddress() != nil {
}
if let _ = p.getContacts()?.printAddress() {
}
let e = p.contacts?.email?["home"]
p.contacts?.email?["home"]?.count
// 딕셔너리가 옵셔널로 선언되어 있고 키를 통해 값을 얻을 때는 [] 앞에 ?를 붙인다.
// [] 뒤에 ?를 붙이는 경우는 서브 스크립트에서 속성에 접근하거나 메소드를 호출 할 때
p.contacts?.address = "Daegu"
p.contacts?.address
optionalP?.contacts?.address = "Deagu"
optionalP?.contacts?.address
Optional Pattern
外来モードを利用して外来マッチングコードをより効果的に作成する方法を学ぶ
let a: Int? = 0
let b: Optional<Int> = 0
if let x = a {
print(x)
}
if case .some(let x) = a {
print(x)
}
if case let x? = a {
print(x)
}
let list: [Int?] = [1, nil, nil, 3, nil, 5]
for item in list {
guard let x = item else { continue }
print(x)
}
for case let x? in list {
print(x)
}
// ---------------
//if a == nil {
//
//}
//
//if a == .none {
//
//}
// nil == .none
// 위 아래 둘 다 같은 코드
// ===============
//if a == 1 {
//
//}
//
//if a == .some(1) {
//
//}
// 1 == .some(1)
// 위 아래 같은 코드
Functions
Variadic Parameters
1つのパラメータで2つ以上の値を渡す可変パラメータを学習します.
(name: Type...)
print("Hello")
print("Hello", "Swift")
func printSum(of nums: Int...) {
var sum = 0
for num in nums {
sum += num
}
print(sum)
}
printSum(of: 1, 2, 3) // 6
printSum(of: 1, 2, 3, 4, 5) // 15
Function Types
(ParameterTypes) -> ReturnType
func sayHello() {
print("Hello, Swift")
}
let f1 = sayHello
f1()
func printHello(with name: String) {
print("hello, \(name)")
}
let f2: (String) -> () = printHello(with:)
let f3 = printHello(with: )
// 함수에 저장할 때는 아그먼트 레이블을 사용하지 않는다
f3("World")
func add(a: Int, b: Int) -> Int{
return a + b
}
var f4: (Int, Int) -> Int = add(a: b: )
f4(1,2)
func add(_ a: Int, with b: Int) -> Int {
return a + b
}
f4 = add(_:with:)
// 입출력
func swapNumbers(_ a: inout Int, _ b: inout Int) {
}
let f5 = swapNumbers(_:_:)
f5
// 가변 파라미터
func sum(of numbers: Int...) {
}
let f6 = sum(of: )
f6
// 현실적인 코드
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
func subtract(_ a: Int, _ b: Int) -> Int {
return a - b
}
func multiply(_ a: Int, _ b: Int) -> Int {
return a * b
}
func divide(_ a: Int, _ b: Int) -> Int {
return a / b
}
typealias ArithmeticFunction = (Int, Int) -> Int
func selectFunction(from op: String) -> ArithmeticFunction? {
switch op {
case "+":
return add(_:_:)
case "-":
return subtract(_:_:)
case "*":
return multiply(_:_:)
case "/":
return divide(_:_:)
default:
return nil // nil을 리턴하려면 반환타입을 옵셔널로 추가해야 됨
}
}
let af = selectFunction(from: "+")
af?(1, 2) // 옵셔널 체이닝 활용
selectFunction(from: "*")?(12, 34)
Nested Functions
関数の内部で新しい関数を実装する方法を学習します
//다른 함수에 포함되어 있는 함수
func outer() -> () -> () {
func inner() { // Nested Functions
print("inner")
}
print("outer")
return inner
}
let f = outer()
f()
//func inner() {
// print("inner")
//}
outer()
Nonreturning Function
呼び出し時にコードを終了したり、異常を投げ出したりする特殊な関数を学習します.
Nonreturning Functionを呼び出し、結果として関数Bodyでプログラミングまたは転送エラーを終了します.
func returnSomething() -> Int {
return 0
}
let result = returnSomething()
print(result)
func returnNothing() {
return
}
returnNothing()
print("done")
func doSomethingAndTerminate() -> Never { // Never = 아무것도 리턴하지 않는다
fatalError("msg") // 프로그램 실행을 종료하는 함수
}
// doSomethingAndTerminate()
print("agter terminate")
// 에러를 던지도록 구현
enum MyError: Error {
case error
}
func doSomethingAndAlwaysThrow() throws -> Never {
throw MyError.error // 에러를 던짐
}
//do {
// try doSomethingAndTerminate()
// print("after try")
//} catch {
// print(error)
//}
//
//
//func terminate() -> Never {
// fatalError("positive only")
//}
//
//func doSomething(with value: Int) -> Int {
// guard value >= 0 else {
// terminate()
// }
// return 0
//}
// doSomething(with: -1)
Closures
Escaping Closure
EscappingとNon Escaptinで実行されるエンクロージャの比較
Closerパラメータは基本的にnon-servate Closerです
func performNonEscapint(closure: () -> ()) {
print("start")
closure()
print("end")
}
// 함수 호출
performNonEscapint {
print("closure")
}
func performEscaping(closure: @escaping () -> ()) { // 파라미터가 escaping 클로저로 선언 됨
print("start")
var a = 12
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // 지연시간
closure()
print(a)
}
print("end")
}
performEscaping {
print("closure")
}
Autoclosure
式をモジュールにカプセル化する@autocrosureプロパティの学習
// 파라미터로 전달 되는 표현을 클로저로 래핑해줌
// 랜덤 넘버를 리턴하는 단순한 함수
func random() -> Int {
return Int.random(in: 0...100)
}
// 정수를 파라미터로 받아서 print 함수로 출력하는 함수
func takeResult(param: Int) {
print(#function)
print(param)
}
takeResult(param: random())
print("-------------------------------")
func takeClosure(param: () -> Int) {
print(#function)
print(param())
}
takeClosure(param: { Int.random(in: 0...100) })
print("-------------------------------")
func takeAutoclosure(param: @autoclosure @escaping () -> Int) { // @autoclosure // 비동기로 호출하려면 @escaping를 추가해야됨
// 오토클로저를 호출하면 파라미터를 호출할 수 없음 -> 파라미터를 항상 비워놔야됨
// 반면 리턴 타입은 원하는 타입으로 선언 할 수 있음
print(#function)
DispatchQueue.main.asyncAfter(deadline: .now() + 1 ) { // 비동기
print(param())
}
}
takeAutoclosure(param: Int.random(in: 0...100)) // @autoclosure로 선언되면 클로저로 사용할 수 없음 -> 자동으로 클로저로 래핑되기 때문에
// 오토클로저를 많이 활용하는 것은 어썰트
let rnd = random()
assert(rnd > 30)
String and Character
String Options
文字列の編集方法の学習
Numeric Option
"A" < "B"
"a" < "B"
// 아스키코드 때매 그럼
let file9 = "file9.txt"
let file10 = "file10.txt"
file9 < file10
file9.compare(file10) == .orderedAscending
file9.compare(file10, options: [.numeric]) == .orderedAscending
// [.numeric] 옵션을 사용하면 문자열에 추가된 숫자를 숫자열로 판단한다
Diacritic Insensitive
let a = "Cafe"
let b = "Cafè"
a == b
a.compare(b) == .orderedSame
a.compare(b, options: [.diacriticInsensitive]) == .orderedSame
// [.diacriticInsensitive] = 발음 기호를 무시함
Width Insensitive Option
let a = "\u{30A1}"
let b = "\u{ff67}"
a == b
a.compare(b) == .orderedSame
// 정각 문자와 반각? 문자를 비교하고 싶지 않으면 Width Insensitive Option 추가
a.compare(b, options: [.widthInsensitive]) == .orderedSame
Forced Ordering Option
// 강제로 정렬
let upper = "STRING".lowercased()
let lower = "string"
upper == lower
upper.compare(lower, options: [.caseInsensitive]) == .orderedSame
upper.compare(lower, options: [.caseInsensitive, .forcedOrdering]) == .orderedSame
// [.forcedOrdering] 옵션은 전체 옵션을 적용했을 때 같은 문자열로 판단된다면 일부 옵션을 무시하고 최대한 문자열의 순서를 파악할 수 있는 값을 리턴해줌
Regular Expression
// 정규식 옵션 = 복잡한 패턴의 문자를 쉽게 검색할 수 있음
// 많이 사용함
let emailPattern = "([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)(\\.[0-9a-zA-Z_-]+){1,2}"
let emailAddress = "[email protected]"
if let _ = emailAddress.range(of: emailPattern) {
print("found")
} else {
print("not found")
}
// Regular Expression 옵션 추가
if let range = emailAddress.range(of: emailPattern, options: [.regularExpression]), (range.lowerBound, range.upperBound) == (emailAddress.startIndex, emailAddress.endIndex) {
print("found")
} else {
print("not found")
}
Character Set
文字セット
文字列の検索または無効な文字の削除に使用
let a = CharacterSet.uppercaseLetters
let b = a.inverted
var str = "loRem Ipsum"
var charSet = CharacterSet.uppercaseLetters
if let range = str.rangeOfCharacter(from: charSet) { // 대문자가 검색된다면 첫번째 결과의 범위를 리턴해준다
print(str.distance(from: str.startIndex, to: range.lowerBound))
}
if let range = str.rangeOfCharacter(from: charSet, options: [.backwards]) { // [.backwards] 옵션 추가
print(str.distance(from: str.startIndex, to: range.lowerBound))
}
str = " A p p l e "
charSet = .whitespaces
// .trimmingCharacters 파라미터로 전달 된 캐릭터셋의 포함되어 있는 문자를 문자열에서 삭제한다 그리고 새로운 문자열로 리턴한다
let trimmed = str.trimmingCharacters(in: charSet)
print(trimmed)
// 양끝 공백 삭제됨
var editTarget = CharacterSet.uppercaseLetters
editTarget.insert("#") // 문자 하나 추가
editTarget.insert(charactersIn: "~!@") // 문자 여러개 추가
editTarget.remove(charactersIn: "BCD")
// 커스텀 캐릭터셋
let customCharSet = CharacterSet(charactersIn: "@.") // 두 개의 문자열로 저장된 캐릭터셋 생성
let email = "[email protected]"
let components = email.components(separatedBy: customCharSet) // 문자열을 분리해주고 리턴함. // .components(separatedBy: )
Reference
この問題について(23. Expert #1), 我々は、より多くの情報をここで見つけました https://velog.io/@jkang4531/23.-Expert-1テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol