07/09/2018, 17:23

Swift - Custom operators - Part 2

Swift - Custom operators - Part 2 Ở Part 1: https://kipalog.com/posts/Swift---Custom-operators---Part-1, mình đã giới thiệu cơ bản về operator và cách custom nó. Trong phần 2 này mình sẽ đi sau tìm hiểu thêm 1 số phần khác nâng cao hơn chút. 1. Generic Operators Bây giờ mình muốn phép luỹ ...

Swift - Custom operators - Part 2

Ở Part 1: https://kipalog.com/posts/Swift---Custom-operators---Part-1, mình đã giới thiệu cơ bản về operator và cách custom nó. Trong phần 2 này mình sẽ đi sau tìm hiểu thêm 1 số phần khác nâng cao hơn chút.

1. Generic Operators
Bây giờ mình muốn phép luỹ thừa apply cho toàn bộ các loại Integer. Code như sau, cũng khá dễ hiểu:

func **<T: Integer>(lhs: T, rhs: Int) -> T {
  var result = lhs
  for _ in 2...rhs {
    result *= lhs
  }
  return result
}
func **=<T: Integer>(lhs: inout T, rhs: Int) {
  lhs = lhs ** rhs
}

Chú ý đến Integer type constrain. Cái ràng buộc cần có bởi vì dòng code: có operator *= không phải loại nào cũng dùng được, phải conform Integer Type mới dùng được. Bây giờ ta test thử với các loại Integer khác nhau:

let unsignedBase: UInt = 2
let unsignedResult = unsignedBase ** exponent

let base8: Int8 = 2
let result8 = base8 ** exponent

let unsignedBase8: UInt8 = 2
let unsignedResult8 = unsignedBase8 ** exponent

let base16: Int16 = 2
let result16 = base16 ** exponent

let unsignedBase16: UInt16 = 2
let unsignedResult16 = unsignedBase16 ** exponent

let base32: Int32 = 2
let result32 = base32 ** exponent

let unsignedBase32: UInt32 = 2
let unsignedResult32 = unsignedBase32 ** exponent

let base64: Int64 = 2
let result64 = base64 ** exponent

Như vậy, nó đúng cho tất cả các loại integer: Int, UInt, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64 and UInt64. Int/ UInt/ Int8 là gì các bạn tự tìm hiểu thêm nha.

2. Precedence and associativity
Nếu chỉ có 2 giá trị thì khá đơn giản nhưng nếu là đoạn code sau thì sao:

2 * 2 ** 3 ** 3 // không thể compile

Swift không thể compile được nếu thiếu các thông tin sau đây:

  • Độ ưu tiên (precedence): Phép nào trước phép nào, nhân trước hay luỹ thừa trước.
  • Độ kết hợp (associativity): Từ trái qua phải trước hay từ phải qua trái trước.

Nếu không có 2 thông tin trên thì có 1 cách duy nhất để Swift hiểu và compile, đó là quăng vào dấu ngoặc đơn:

 2 * (2 ** (3 ** 2))

Để tránh khỏi sự phiền hà, ta chỉ cần define ra precedence group như sau:

precedencegroup ExponentiationPrecedence {
  associativity: right
  higherThan: MultiplicationPrecedence
}
infix operator **: ExponentiationPrecedence

Cái mà mình define ở trên là ưu tiên phép luỹ thừa trên phép nhân (MultiplicationPrecedence), và phép tính sẽ là từ phải sang trái (associativity: right). Bây giờ thì Swift có thể compile mà không cần thêm gì nữa.

Như vậy, qua 2 phần, mình đã giới thiệu thêm cho các bạn cụ thể về Custom Operators. Hi vọng các bạn có thêm được phần kiến thức bổ ích cho mình.

0