داشتم در مورد «مطابقت الگو» توی سوییفت میخوندم، که یه عملگر چشمم رو گرفت!!؛ اونم عملگر اختصاصی سوییفت برای این کار بود: =~ . از این عملگر میشه بعنوان مثال، توی بررسی کد HTTP پاسخ سرور استفاده کرد؛ که مثلا اگه موفق نبوده، کد دریافتی توی چه محدودهای هست.
if 400..<500 ~= error.code, error.code != 401 { //Handle Error }
با اینکه ازش استفاده میکردم، ولی هیچ تصوری نداشتم که دقیقا داره چجوری کار میکنه؛ و حتی نمیدونستم که خودمون هم میتونم عملگرهای دلخواه خودمون رو داشته باشیم. تا اینکه از گوگلجان کمک گرفتم، و اونم هرچی میخواستم رو در اختیارم قرار داد. ?
? توی این صفحه میتونین لیستی از عملگرهای سوییفت رو ببینین.
توی سوییفت، عملگرها توی چهار دستهبندی تقسیم میشن:
<Value1> ? <Value2> : <Value3>
? توی سوییفت، راهی برای پیادهسازی عملگر دلخواه از دسته Ternary وجود نداره.
خب. الان میخوایم برای نمونه، یه عملگر بسازیم تا جذر یه عدد رو بهمون بده. بهترین و قشنگترین کاری که میتونیم انجام بدیم، اینه که کاراکتر مربوط به اون عملگر رو برابر ( √ ) قرار بدیم!! ?
? توی سوییفت تابعی هست به نام sqrt که میاد و جذر عدد ورودی خودش رو برمیگردونه. مام در نهایت از همین تابع استفاده خواهیم کرد؛ البته با روشی بمراتب خوشگلتر!!
برای پیادهسازی این عملگر، طبیعی هست که باید از نوع Prefix باشه، و نحوه استفادهاش هم چیزی شبیه به این خواهد بود:
let someVal = 25 let squareRoot = √someVal // result is 5
prefix operator √
prefix func √(lhs: Double) -> Double { return sqrt(lhs) }
تمام!! نمونه اجراییاش هم میشه اینجوری:
prefix operator √ prefix func √(lhs: Double) -> Double { return sqrt(lhs) } let number: Double = 36 let squareRoot = √number print(squareRoot) // 6.0
این عملگر دلخواه ما، دو تا مقدار به نامهای lhs و rhs قبول میکنه و مجموع مربعات اونا رو برمیگردونه. بعنوان مثال اگه ورودیهاش ۲ و ۳ باشه، مقدار ۱۳ رو برمیگردونه.
خب، مثل توضیحات قبلی، قدم به قدم میریم جلو.
infix operator ◉
infix func ◉(lhs: Double, rhs: Double) -> Double { return lhs * lhs + rhs * rhs }
اگه کدهای تا اینجا رو اجرا بگیرین، کامپایلر بهتون یه همچین خطایی رو نشون میده:
error: ‘infix’ modifier is not required or allowed on func declarations
برای رفع خطا، فقط کافیه کلمه infix رو از تعریف تابع حذف کنیم.
تا اینجا ما یه عملگر اختصاصی با علامت و بدنه دلخواهمون تعریف کردیم. البته اینم در نظر بگیرین که این تمام ماجرا نیست، و یه قسمتی از تعریف این عملگر، از تنظیمات پیشفرض استفاده کرده. موارد دیگهای که میتونیم برای عملگرمون تعریف کنیم (و در مواردی هم باید این کار رو انجام بدیم)، تقدم و شرکتپذیری عملگر هست، که در ادامه توضیحش رو میدیم.
برای دیدن توضیحات در مورد تقدم و شرکتپذیری میتونین این صفحه در مورد ترتیب عملگرها و این صفحه در مورد تعریف عملگرها رو مطالعه کنین.
یکی از مهمترین نکات توی تعریف عملگرها، تقدم (Precedence) و شرکتپذیری (Associativity) هست. این صفحه مستندات رسمی اپل برای این نکات توی سوییفت هست.
بطور کلی،
تقدم عملگرها، به بعضی از عملگرها اولویت بالاتری نسبت به بقیه عملگرها میده. این اولویت توی اجرا خودش رو نشون میده و عملگرهای با اولویت بالاتر، زودتر اجرا میشن.
شرکتپذیری عملگرها، این رو مشخص میکنه که عملگرهای دارای اولویت یکسان یا برابر، به چه صورتی باهم دستهبندی میشن؛ به سمت چپ دستهبندی میشن یا به سمت راست.
مثال زیر، نمونهای از عملگرهایی هست که به سمت چپ دستهبندی میشن:
v1 + v2 + v3 == (v1 + v2) + v3
ترتیب اولویت عملگرهای سوییفت توی شکل زیر قابل مشاهدهست.
برای دیدن لیست کامل عملگرهای سوییفت و توضیحات مربوط به اونا، مستندات رسمی اپل در مورد عملگرهای سوییفت رو بخونین.
عملگری که تعریف کردیم، دارای اولویت تعریفشده نیست. خودمون باید براش یه اولویت تعریف کنیم.
precedencegroup SquareSumOperatorPrecedence { lowerThan: MultiplicationPrecedence higherThan: AdditionPrecedence associativity: left assignment: false }
توی کد بالا، ما یه گروه اولویت جدید ساختیم که اولویت اجراییش از AdditionPrecedence بیشتره، و از MultiplicationPrecedence کمتره و به سمت چپ دستهبندی میشه.
مقادیر none و یا left و یا right ، مقادیر قابل قبول برای associativity هستن.
توضیح در مورد assignment ، توی نسخه اصلی مقاله هست. خوندمش، ولی چون نتونستم درست متوجه بشم یا منظور رو برسونم، از ذکر توضیحش خودداری کردم.
infix operator ◉: SquareSumOperatorPrecedence
در نهایت کد ما یه همچین چیزی میشه:
//Create PrecedenceGroup precedencegroup SquareSumOperatorPrecedence { lowerThan: MultiplicationPrecedence higherThan: AdditionPrecedence associativity: left assignment: false } //Create Infix Operator infix operator ◉: SquareSumOperatorPrecedence //Define Infix Operator func ◉(lhs: Double, rhs: Double) -> Double { return lhs * lhs + rhs * rhs } let a: Double = 2 let b: Double = 3 let squareSum = a ◉ b print(squareSum) // 13.0
struct Vector2D { var x = 0.0 var y = 0.0 } extension Vector2D { static func + (lhs: Vector2D, rhs: Vector2D) -> Vector2D { return Vector2D(x: lhs.x + rhs.x, y: lhs.y + rhs.y) } }
prefix operator ++++ prefix func ++++<T: Numeric>(lhs: T) -> T { return lhs * 4 } let n = 12 let m = ++++n print(m) // 48
منبع مطلب: این مطلب رو بر اساس این پست نوشتم.