Open JooYoungNoh opened 6 months ago
가독성과 표현성 특정 연산이나 복잡한 연산을 코드를 읽기 쉽고 간결하게 만들 수 있음
확장성 특정 작업을 위한 연산자가 없는 경우 커스텀 연산자를 만들어 연산이 가능하게 할 수 있음
편의성 특정 작업을 반복적으로 수행해야 할 때 커스텀 연산자를 만들어 코드의 반복성을 줄이고 작업을 단순화할 수 있음
가독성과 목적
중복 사용 주의
남용 금지
우선순위 및 결합성
규칙 준수
주석
테스트
네이밍
//문자열들을 더할 때 공백을 넣어서 합쳐주는 연산자
//합칠때 사용하는 + 를 이용하면서 커스텀 연산자 표시를 <>로 명학하게 해줌
infix operator <+>: AdditionPrecedence
extension String {
static func <+>(lhs: String, rhs: String) -> String {
return lhs + " " + rhs
}
}
// 테스트
let fullName = "노" <+> "주영"
print(fullName) // 노 주영
prefix operator 연산자이름
static prefix func 연산자(파라미터) -> 반환타입 {
//연산 방식
}
// C언어에 있는 +1 해주는 메서드
prefix operator ++
prefix func ++ (value: inout Int) {
value += 1
}
var number = 5
++number //number가 1 증가
print(number) //6
postfix operator 연산자이름
static postfix func 연산자(파라미터) -> 반환타입 {
//연산 방식
}
// 팩토리얼
// 원래는 ! 인데 옵셔널 바인딩 기호와 같음으로 ~*로 하겠음
postfix operator ~*
postfix func ~* (value: Int) -> Int?{
if value > 0 {
var result = 1
for i in 1...value {
result *= i
}
return result
}
print("0보다 큰 정수를 넣어주세요")
return nil
}
print((4~*)!) //24
print(0~*)
//0보다 큰 정수를 넣어주세요
//nil
infix operator 연산자이름
또는
infix operator 연산자이름: Precedencegroup
static func 연산자(파라미터) -> 반환타입 {
//연산 방식
}
// 행렬 사칙연산
struct Matrix {
let rows: Int
let columns: Int
var grid: [[Double]]
init(rows: Int, columns: Int, grid: [[Double]]) {
self.rows = rows
self.columns = columns
self.grid = grid
}
// 행렬 덧셈 연산자
static func + (left: Matrix, right: Matrix) -> Matrix? {
guard left.rows == right.rows && left.columns == right.columns else {
return nil // 행과 열의 크기가 다르면 덧셈을 할 수 없으므로 nil 반환
}
var result = Matrix(rows: left.rows, columns: left.columns, grid: Array(repeating: Array(repeating: 0.0, count: left.columns), count: left.rows))
for i in 0..<left.rows {
for j in 0..<left.columns {
result.grid[i][j] = left.grid[i][j] + right.grid[i][j]
}
}
return result
}
// 행렬 뺄셈 연산자
static func - (left: Matrix, right: Matrix) -> Matrix? {
guard left.rows == right.rows && left.columns == right.columns else {
return nil // 행과 열의 크기가 다르면 뺄셈을 할 수 없으므로 nil 반환
}
var result = Matrix(rows: left.rows, columns: left.columns, grid: Array(repeating: Array(repeating: 0.0, count: left.columns), count: left.rows))
for i in 0..<left.rows {
for j in 0..<left.columns {
result.grid[i][j] = left.grid[i][j] - right.grid[i][j]
}
}
return result
}
// 행렬 곱셈 연산자
static func * (left: Matrix, right: Matrix) -> Matrix? {
guard left.columns == right.rows else {
return nil // 첫 번째 행렬의 열 수와 두 번째 행렬의 행 수가 일치하지 않으면 곱셈을 할 수 없으므로 nil 반환
}
var result = Matrix(rows: left.rows, columns: right.columns, grid: Array(repeating: Array(repeating: 0.0, count: right.columns), count: left.rows))
for i in 0..<left.rows {
for j in 0..<right.columns {
var sum = 0.0
for k in 0..<left.columns {
sum += left.grid[i][k] * right.grid[k][j]
}
result.grid[i][j] = sum
}
}
return result
}
// 행렬 나눗셈 연산자
static func / (left: Matrix, right: Matrix) -> Matrix? {
guard let rightInverse = right.inverse() else {
return nil // 오른쪽 행렬의 역행렬이 존재하지 않으면 나눗셈 불가능
}
return left * rightInverse
}
}
extension Matrix {
// 행렬의 역행렬 계산 메서드
func inverse() -> Matrix? {
guard self.rows == self.columns else {
return nil // 정사각 행렬이 아니면 역행렬이 존재하지 않으므로 nil 반환
}
// 단위 행렬 생성 E
var identity = Matrix(rows: self.rows, columns: self.columns, grid: Array(repeating: Array(repeating: 0.0, count: self.columns), count: self.rows))
for i in 0..<self.rows {
identity.grid[i][i] = 1
}
// 기존 행렬 복사
var copy = self
// 가우스-조르단 소거법 적용
for i in 0..<copy.rows {
// 대각원소가 0인 경우 교환
if copy.grid[i][i] == 0 {
var found = false
for j in (i + 1)..<copy.rows {
if copy.grid[j][i] != 0 {
copy.grid.swapAt(i, j)
identity.grid.swapAt(i, j)
found = true
break
}
}
// 대각원소가 0이면 역행렬이 존재하지 않음
if !found {
return nil
}
}
// 대각원소를 1로 만듦
let divisor = copy.grid[i][i]
for j in 0..<copy.columns {
copy.grid[i][j] /= divisor
identity.grid[i][j] /= divisor
}
// i번째 열을 0으로 만듦
for k in 0..<copy.rows {
guard k != i else { continue }
let multiplier = copy.grid[k][i]
for j in 0..<copy.columns {
copy.grid[k][j] -= multiplier * copy.grid[i][j]
identity.grid[k][j] -= multiplier * identity.grid[i][j]
}
}
}
return identity
}
}
let matrixA = Matrix(rows: 2, columns: 2, grid: [[1, 2], [3, 4]])
let matrixB = Matrix(rows: 2, columns: 2, grid: [[5, 6], [7, 8]])
let add = matrixA + matrixB
let sub = matrixA - matrixB
let mul = matrixA * matrixB
let div = matrixA / matrixB
print(add!) // Matrix(rows: 2, columns: 2, grid: [[6.0, 8.0], [10.0, 12.0]])
print(sub!) // Matrix(rows: 2, columns: 2, grid: [[-4.0, -4.0], [-4.0, -4.0]])
print(mul!) // Matrix(rows: 2, columns: 2, grid: [[19.0, 22.0], [43.0, 50.0]])
print(div!)
// Matrix(rows: 2, columns: 2, grid: [[2.9999999999999982, -1.9999999999999982], [2.0, -0.9999999999999982]])
// 컴퓨터라 그럼
// Matrix(rows: 2, columns: 2, grid: [[3.0, -2.0], [2.0, -1.0]]) 과 같음
4 *+* 2 + 3 //error!
커스텀 연산자의 계산 후에 3을 더해서 19라는 결과를 얻고 싶어 위와 같이 시도했지만 에러 등장 커스텀 연산자의 우선순위를 지정하지 않아서 default precedence group에 소속됨 다른 연산자와 함께 연산을 수행하면 스위프트에서 어느 연산을 먼저 수행해야 하는지 알 수 없어 에러가 발생 이 문제를 해결하기 위해 우선순위를 지정해줘야함
infix operator 연산자이름: PrecedenceGroup
또는
precedencegroup CustomGroup {
higherThan: PrecedenceGroup
lowerThan: PrecedenceGroup
associativity: 결합성
assignment: 할당여부
}
infix operator 연산자이름: CustomGroup
higherThan
lowerThan
associativity
assignment
infix operator *+*: MultiplicationPrecedence
extension Int { static func +(lNum : Int, rNum : Int) -> Int { return lNum rNum 2 } }
print(4 + 2 + 3) //19
<br/>
<br/>
- **커스텀 우선순위 그룹 사용**
```Swift
// 지수의 우선순위 1
precedencegroup ExponentiationPrecedence {
associativity: right
higherThan: MultiplicationPrecedence
}
// 우선순위 지정
infix operator **: ExponentiationPrecedence
func **(base: Double, exponent: Double) -> Double {
return pow(base, exponent)
}
print(2 ** 3 ** 2) // 512, 2 ** (3 ** 2)과 같음
// 지수의 우선순위 2
precedencegroup ExponentiationPrecedence {
associativity: left
higherThan: MultiplicationPrecedence
}
// 우선순위 지정
infix operator **: ExponentiationPrecedence
func **(base: Double, exponent: Double) -> Double {
return pow(base, exponent)
}
print(2 ** 3 ** 2) //64, (2 ** 3) ** 2과 같음
커스텀 연산자를 표시할 땐 <>를 표시해줘야 한다고 했는데, 제네릭도 <>를 표시해 주잖아요? 그러면 제네릭도 일종의 커스텀 연산자일까요?