-
تعداد ارسال ها
45 -
تاریخ عضویت
-
روز های برد
14
آخرین بار برد سید محمد عباسی در 1 اسفند 1398
سید محمد عباسی یکی از رکورد داران بیشترین تعداد پسند مطالب است !
اعتبار در سایت
35 عالیدرباره سید محمد عباسی
توسعه دهنده بَک اِند
توسعه دهنده فرانت اِند
توسعه دهنده فرانت اِند
- تاریخ تولد 9 آذر 1378
موقعیت
-
شهر
استان اصفهان_شهرستان فلاورجان
آخرین بازدید کنندگان نمایه
2,228 بازدید کننده نمایه
-
آموزش زبان برنامهنویسی سوئیفت - جلسه آخر مواردی که در این جلسه یاد خواهید گرفت: کلاسها و ساختارها در این جلسه که جلسهی آخر است، ما به بررسی مبحث کلاسها و ساختار داده خواهیم پرداخت. اول از همه بگذارید تا تعریفی از کلاس و ساختار داده داشته باشیم و سپس به بقیهی موارد خواهیم پرداخت. کلاسها ( Classes ) چیستند؟ یک کلاس واقعی را در نظر بگیرید که از تعدادی زیاد یا کمی دانشآموزان تشکیل شده است. نام کلاس به عنوان مثال میتواند کلاس کامپیوتر-۲ باشد! و معلم و دانشآموزان هم اعضای آن کلاس هستند. معلم یک وظیفه دارد و دانشآموزان هم وظیفهای دیگر...، در دنیای برنامهنویسی هم ما کلاسها را داریم که در پروژهمان به کمک ما میآیند. کلاسها، متشکل ویژگیها ( Properties ) و متدها ( Methods ) هستند که میتوانند به صورت اختیاری به کلاسها اضافه شوند. در سوئیفت شما میتوانید بدون هیچ رابط یا فایلی، کلاسهای خودتان را در یک فایل واحد تعریف کنید. نکته یک نمونه از یک کلاس، به طور معمول به عنوان یک شئ ( Object ) شناخته میشود؛ اما کلاسها و ساختار به دلیل اینکه از نظر عملکرد با سایر زبانهای برنامهنویسی، مثل هم هستند، از اصطلاح عمومیتر آن، یعنی نمونه استفاده میشود. ساختار داده ( Structure ) چیستند؟ ساختار داده هم دقیقا مانند کلاسها هستند؛ که ثوابت، متغییرها و توابع را در خود ذخیره میکنند. تعریف کلاس و ساختار نحوهی تعریف کلاس و ساختار در سوئیفت، مشابه هم است! به این مثال دقت کنید؛ class Languages { // Class definition goes here } struct DataTypes { // Structure dfinition goes here } همانطور که مشاهده کردید، ما با استفاده از کلمهی کلید class یک کلاس به نام Languages تعریف کرده و سپس با دو براکت {} باز و بسته، میتوانیم کُدهای خودمان را بنویسیم. در مقابل میبینید که تعریف ساختار داده، مشابه کلاس است! ابتدا کلمهی کلید struct را نوشته و سپس یک نام برای آن انتخاب میکنیم. قوائد نامگذاری در کلاسها و ساختار داده، به صورت پاسکال کِیس ( PascalCase ) هستش. یعنی حرف اول هر کلمه میبایست بزرگ نوشته شود و مابقی کلمه به حروف کوچک. مانند؛ ProgrammingLanguages. با یک مثال بهتر و شفافتر، این موضوع را برای شما قابل درکتر خواهیم کرد؛ class FullName { var first_name : String? var last_name : String? // Set function func setFullName(_ first_name : String, _ last_name : String ) { self.first_name = first_name self.last_name = last_name } // Get function func getFullName() -> String { return "First name is : \(self.first_name!)\n" + "Last name : \(self.last_name!)" } } struct DataTypes { let _age : Int let _name : String let _average : Double } let _full_name = FullName() let _datatype = DataTypes(_age: 20,_name: "Mohammad",_average: 20.0) _full_name.setFullName("Mohammad", "Abasi") print(_full_name.getFullName()) print("Age is : \(_datatype._age)") print("First name is : \(_datatype._name)") print("Average is : \(_datatype._average)") همانطور که مشاهده میکنید، یک کلاس با نام FullName تعریف شده و یک کلاس هم با نام DataTypes. در کلاس FullName ما دو متغییر و دو تابع داریم و در طرف دیگر ما ساختار دادهی DataTypes را خواهیم داشت که دارای سه متغیر میباشد ( age_, _name,_average ) که برای ذخیرهی دادههای مرتبط استفاده میشوند. در ادامه ما دو شئ از کلاس FullName و DataTypes ساختهایم که در ادامه از ویژگیها و همچنین متُدهای آن استفاده کردهایم ( به خطوط ۱۹ تا ۲۳ دقت کنید ). نکته متُد، همانند تابعی است که مجموعهای از کدها را هنگامی که فراخوانی شده باشد، اجرا میکند و به این خاطر به تابع تفاوت دارد که تابع به صورت مجزا نوشته میشود و متُد در داخل کلاس تعریف میشود. همچنین شما میتوانید نوع ساختار دادهای را که تعریف کردید، را در کلاس به کار ببرید! به این مثال توجه کنید؛ class FullName { var first_name : String? var last_name : String? var data_types = DataTypes() // Set function func setFullName(_ first_name : String, _ last_name : String ) { self.first_name = first_name self.last_name = last_name } // Get function func getFullName() -> String { return "First name is : \(self.first_name!)\n" + "Last name : \(self.last_name!)" } } struct DataTypes { var age : Int = 0 var name : String = "" var average : Double = 0 } let _full_name = FullName() var _datatype = DataTypes() _datatype.age = 20 _datatype.name = "Mehdi" _datatype.average = 17.15 _full_name.setFullName("Mohammad", "Abasi") print(_full_name.getFullName()) print("Age is : \(_datatype.age)") print("First name is : \(_datatype.name)") print("Average is : \(_datatype.average)") _full_name.data_types.age = 20 _full_name.data_types.name = "Mohammad" _full_name.data_types.average = 20.0 print("Name is : \(_full_name.data_types.name)\nAnd Age is : \(_full_name.data_types.age)\nAnd Average is : \(_full_name.data_types.average)") ما از همان ساختار قبلی ( DataTypes ) استفاده کردیم و برای اینکه بتوانیم از آن در کلاسمان استفاده کنیم، لازم است مقداردهی را در ساختار داده ( به خطوط ۱۳ تا ۱۷ دقت کنید ) انجام دهید یا اینکه در خود کلاس و هنگامی که متغییر از نوع ساختار داده تعریف میکنید ( data_types ) در سازندهی آن بین دو پرانتز ()، مقادیر را وارد کنید، همانند زیر؛ class FullName { var first_name : String? var last_name : String? var data_types = DataTypes(age : 0, name : "", average : 0) // Set function func setFullName(_ first_name : String, _ last_name : String ) { self.first_name = first_name self.last_name = last_name } // Get function func getFullName() -> String { return "First name is : \(self.first_name!)\n" + "Last name : \(self.last_name!)" } } struct DataTypes { var age : Int var name : String var average : Double } let _full_name = FullName() var _datatype = DataTypes(age : 20, name : "Mohammad", average : 20) _datatype.age = 20 _datatype.name = "Mehdi" _datatype.average = 17.15 _full_name.setFullName("Mohammad", "Abasi") print(_full_name.getFullName()) print("Age is : \(_datatype.age)") print("First name is : \(_datatype.name)") print("Average is : \(_datatype.average)") _full_name.data_types.age = 20 _full_name.data_types.name = "Mohammad" _full_name.data_types.average = 20.0 print("Name is : \(_full_name.data_types.name)\nAnd Age is : \(_full_name.data_types.age)\nAnd Average is : \(_full_name.data_types.average)") پس باید حتما در ساختارهای داده، مقداردهی را هم انجام دهید، فرقی نمیکند که شما ساختار دادهیتان را به صورت مجزا تعریف میکنید یا برای استفاده در کلاس! در هر صورت، باید مقداردهی را انجام دهید و این الزام است! یادتان باشد که اگر مقداردهی را در سازندهی ( Constructor ) ساختار داده، انجام داده باشید و بخواهید که به صورت مستقیم و بدون دخالت در تغییر نوعهای دادهی آن، از آن استفاده کنید، میتوانید کلمهی کلید let را برای ساختار دادهی خود به کار ببرید ( ()let _data_datatype = DataTypes ) و اما اگر نه، بخواهید در ادامهی پروژهیتان، مقادیر ویژگیهای آن را تغییر دهید، باید از کلمهی کلید var استفاده کنید! نه تنها در تعریف یک شئ ساختار داده، بلکه برای تغییر ویژگیهای آن هم باید از همین کلمهی کلید استفاده کنید تا مجوز تغییر دادهها را داشته باشید. پس به این نکته هم دقت داشته باشید. هنگامی که شما یک نمونه از کلاس یا ساختار داده ایجاد میکنید، میتوانید در سازندهی آن، ویژگیها کلاس یا ساختار داده را مقداردهی کنید، به این شکل؛ struct Website { var name : String var subject : String } class Project { var version : Float? var name : String? init (version : Float, name : String) { self.version = version self.name = name } } var website = Website(name : "iostream.ir", subject : "Programming and Graphic Business and .... ") var project = Project(version : 2.1, name : "Fanoox") print(website.name) print(website.subject) print() print(project.version!) print(project.name!) دقت کنید که سازنده با کلمهی کلید func همراه نمیشود! بلکه از طریق کلمهی کلید init باید سازنده را تعریف و به آن پارامتر داد. همانند مثال بالا که مشاهده میکنید. در هنگامی که از دو ویژگی version و name استفاده میکنید، باید با علامت تعچب ( ! ) آن را از حالت Wrap به Unwrap کنید! یا به اصطلاح آن را از حالت بستهبندی شده، خارج کنید.
-
سید محمد عباسی تصویر نمایه خود را تغییر داد
-
آموزش زبان برنامهنویسی سوئیفت - جلسه دهم مواردی که در این جلسه یاد خواهید گرفت: توابع بینام ( Closures ) و نوعهای شمارشی توابع بینام ( Closures ) چیستند؟ به زبان ساده، توابعی هستند که نامی ندارند! این توابع در واقع به یک متغییر انتساب داده میشوند و بعد از آن مورد استفاده قرار میگیرند. سوال؛ تفاوت بین این توابع با توابع معمولی چیست؟ پاسخ؛ اگر در روند پروژهتان بخواهید که تابعی داشته باشید که فقط و فقط یکبار اجرا شده و پس از آن دیگر استفاده از آن نداشته باشید و یا بخواهید که یک تابع جزئی از کد شما نباشد، میتوانید از توابع بینام استفاده کنید. در واقع این نوع توابع، از آنجایی که نامی ندارند، باید به یک متغییر انتساب داده شوند تا بتوان آنها را مورد استفاده قرار داد. اجازه بدهید که با یک مثال، به کنجکاوی شما پاسخ دهیم! در حالت کلی، Syntax ( نحو ) کلی تعریف یک تابع بینام به این شکل است؛ { (Parameters) -> ReturnType in // Statments } همانطور که مشاهده میکنید، حالت کلی تعریف یک تابع بینام به این صورت است. ابتدا شما باید دو آکولاد {} تعریف کنید که دستورات شما داخل این بدنه قرار میگیرند و سپس باید نوع دادهٔ برگشتی را تعیین کنید. نکتهٔ مهمی که وجود دارد، کلمهٔ کلیدی in است. این کلمهٔ کلید مشخص میکند که پارامترهای که به تابع میدهید، باید از هم جدا شوند! درواقع در حالت معمولی تعریف یک تابع، شما نیازی به این کلمهٔ کلیدی ندارید، اما در توابع بینام برای اینکه پارامترها از هم جدا شوند، استفاده از این کلمهٔ کلیدی الزامی و لازم است. اگر بخواهیم یک مثال بزنیم تا برایتان شفافتر شود، فرض کنید میخواهیم نام و نام خانوادگی شخصی را گرفته، کمی آن را استایلدهی کنیم و سپس به آن را به تابع برگردانیم! برای این منظور، به این شکل عمل خواهیم کرد؛ یک تابع معمولی همانطور که در جلسهٔ قبل گفته شده، به این صورت تعریف میشود؛ func getFullName(_ first_name: String, _ last_name: String) -> String { let _full_name = "First Name is : \(first_name) and Last Name is : \(last_name)" return _full_name } print(getFullName("Mohammad", "Abasi")) // First Name is : Mohammad and Last Name is : Abasi اما این داستان در توابع بینام کمی فرق میکند و تعریف آن به این صورت است؛ let _full_name = { (_ first_name: String, _ last_name: String) -> String in let _full_name = "First Name is : \(first_name) and Last name is : \(last_name)" return _full_name } print(_full_name("Mohammad", "Abasi")) ملاحضه میکنید که ما دو پارامتر از نوع رشته با نامهای first_name و last_name تعریف کرده و نوع برگشتی آن را هم String ( رشته ) قرار دادهایم، فراموش نکنید که حتما باید از کلمهٔ کلیدی in بعد از مشخص کردن نوع دادهٔ برگشتی استفاده کنید؛ در غیر اینصورت، با این خطا مواجه خواهید شد؛ main.swift:1:20: error: expected ',' separator var closuer = { (_ first_name: String, _ last_name: String) -> String ^ , main.swift:3:42: error: use of unresolved identifier 'first_name' let _full_name = "First Name is : \(first_name) and Last name is : \(last_name)" ^~~~~~~~~~ main.swift:3:75: error: use of unresolved identifier 'last_name' let _full_name = "First Name is : \(first_name) and Last name is : \(last_name)" ^~~~~~~~~ main.swift:1:15: error: unable to infer complex closure return type; add explicit type to disambiguate var closuer = { (_ first_name: String, _ last_name: String) -> String ^ پس آن ( in ) را فراموش نکنید. در بدنهٔ تابع، ما یک ثابت ( let ) تعریف کرده و سپس یک رشته کامل همراه با پارامترها به آن انتساب میدهیم و در آخر آن را به تابع برگشت ( return ) میدهیم. علاوه بر اینکه شما میتوانید به این صورت عمل کنید ( انتساب تابع به متغییر ) میتوانید بدون متغییر اینکار را هم بکنید! فرض کنید میخواهیم دو عدد را با هم جمع بزنیم و فقط میخواهیم یکبار برایمان اینکار انجام شود. برای این منظور به این صورت میتوانیم عمل کنیم؛ let _addition = { (_ number_one: Double, _ number_two: Double) -> Double in return number_one + number_two }(10,20) print(_addition) // Result is = 30 یا print({ (_ number_one: Double, _ number_two: Double) -> Double in return number_one + number_two }(10,20)) // Result is = 30 همانطور که مشاهده میکنید، در دو حالت یکی هستند، تنها تفاوتی که وجود دارد، بعد از آخرین آکولاد ( { ) است. یعنی این قسمت؛ {(10,20)) // Result is = 30 شما در این قسمت و در بین دو پرانتز () به پارامترهایی که تعیین کردهاید، آرگومانهای خودتان را ارسال میکنید ( در این مثال؛ ۱۰ و ۲۰ ) و در نتیجه، به جای اینکه یک تابع برگشت داده شود، یک نتیجه را به دنبال خواهد داشت. اگر اینکار را نکنید و با تابع print بخواهید ببینید که بدون آرگومان دادن، چه اتفاقی خواهد افتاد، نتیجه در خروجی یا تابع خواهد بود؛ print({ (_ number_one: Double, _ number_two: Double) -> Double in return number_one + number_two }) // Result is = (Function) اگر قصد شما این است که نتیجه را در همان زمان مورد استفاده قرار دهید، استفاده از دو روش بالا، جوابگوی شماست و اگر خواستید یک تابع داشته باشید که یک کار مشخص را انجام داده و بعد از آن دیگر مورد استفاده قرار نگیرد، میتوانید از حالت اول استفاده کنید. مرتب سازی عناصر با توابع بینام ( Sort Elements in Closures ) شما میتوانید عناصر یک آرایه را با استفاده از توابع بینام، مرتب کنید! در این نوع مرتبسازی بستگی به شما دارد که چگونه بخواهید عمل مرتبسازی را انجام دهید. بگذارید مثالی را ارائه دهیم تا موضوع را بیشتر و بهتر درک کنید و سپس به سراغ توضیحات تکمیلی خواهیم رفت؛ let _numbers = [1,3,2,4,6,5] var sorted_numbers = _numbers.sorted(by: { (_ number_one: Int, _ number_two: Int) -> Bool in return number_one < number_two }) print(sorted_numbers) همانطور که در قطعه کد بالا مشاهده میکنید، ابتدا یک آرایه تعریف کردهایم ( [let _numbers = [1,3,2,4,6,5 ) و سپس یک متغییر دیگر با نام ( sorted_numbers ) تعریف کرده که خود یک آرایه است! به این دلیل میگویم آرایه، که متد sotred یک آرایه را برمیگرداند. کار این متد مرتبسازی یک آرایه براساس آرگومانیست که شما به آن میدهید. این متد از کلاس آرایه است ( numbers.sorted_ ). بیاید به تشریح آرگومانی که دریافت میکنید، بپردازیم. البته ملاحظه میکنید که آرگومان، یک تابع بینام است! شما میتوانید با برچسب :by تابع بینام خود را تعریف کرده و سپس متد sorted کار خود را شروع میکند و به مرتبسازی اعضای آرایه میپردازد. شما در تابع بینامی که تعریف میکنید باید دو پارامتر را در نظر بگیرید. واضح است که دو پارامتر برای اعضای آرایه است که قرار است در بدنهٔ تابع مورد بررسی قرار گیرند و نتیجهٔ نهایی به تابع sorted داده شود. ما دو پارامتر به نامهای ( number_one, number_two ) تعریف کردهایم که هر دو از نوع عددی هستند ( با توجه به نوع دادهٔ آرایه خود باید پارامترها را مشخص کنید ) و سپس نوع برگشتی را Bool انتخاب کردیم که نتیجهٔ true یا false را برمیگرداند. و در نهایت کلمهٔ کلید in که برای توابع بینام همانطور که گفته بودیم، لازم و اجباریست. در بدنهٔ تابع، چیزی جز یک دستور نخواهیم داشت! با استفاده از دستور return number_one < number_two میگویم اگر عدد اوله ( عضو اول آرایه ) از عدد دوم ( عضو دوم آرایه ) کوچکتر بود، نتیجه true ( درست ) را برگردان و در غیر اینصورت false ( نادرست ) را برگردان. از آنجایی که عدد اول یعنی ۱، کوچکتر از عدد دوم یا همان عضو ۳ است، بنابراین true یا همان درست به تابع برگشت داده میشود که در نتیجه عدد ۱ از آرایه، در جای خود باقی میماند. اما در تکرار بعدی، عدد اول یعنی ۳ کوچکتر از عدد ۲ نیست و نتیجهٔ false یا نادرست برگشت داده خواهد شد که در نهایت عدد ۲ در جایگاه عدد ۳ قرار میگیرد و الی آخر... . این هم یک نمونه از کاربرد توابع بینام بود که با متد sorted از کلاس آرایه همکاری کرد تا به مرتبسازی یک آرایه بپردازد. شما همچنین میتوانید از خلاقیت خود استفاده کنید و کدنویسی زیباتر و خلاقانهتری انجام دهید. شروع کنید و لذت ببرید! نوعهای شمارشی ( Enumerations ) چیستند؟ نوعهای شمارشی یک نوع دادهایست که شامل گروهی از دادهها مرتبط با هم هستند! در مقابل هم باعث خوانایی بیشتر پروژهٔ نرمافزاری خواهد شد. بگذارید باز هم با یک مثال شروع کنیم تا در توضیحات برای شما عزیزان، شفافتر و قابل درکتر شود. برای تعریف یک enum میبایست از Syntax زیر استفاده کنیم؛ enum EnumName { // Enumeration values are described here } همانطور که مشاهده میکنید، حالت کلی تعریف آن به این صورت است. ابتدا کلمهٔ کلید enum را آورده که مشخص کنندهٔ تعریف یک نوع شمارشی است و سپس باید یک نام هم برای آن در نظر بگیرید ( حتما نامی را انتخاب کنید که بیانگر کاری است که انجام میدهد ) و در نهایت در بین دو آکولاد {} میتوانید دادههای خود که مرتبط با نام است تعریف کنید! به این مثال به دقت نگاه کنید؛ enum ProgrammingLanguages { case C case Java case Rust case R case Python case PHP case Javascript case HTML case Perl case Ruby case Swift } var language = ProgrammingLanguages.C print("\(Language) is programming language!") // C is programming language! در قطعه کد بالا همانطور که ملاحضه کردید، ما یک نوع شمارشی به نام ProgrammingLanguages تعریف کردهایم که به معنی زبانهای برنامهنویسی است و درواقع دادههای آن هم مرتبط با برنامهنویسی هستند نه چیزی دیگر! به عنوان مثال ( C,Java,Rust و ... ) همهٔ آنها مرتبط با برنامهنویسی هستند و به خاطر همین است که ما به آنها میگویم گروهی از دادهها که با هم مرتبط هستند! اگر یادتان باشد، گفته بودیم که نوعهای شمارشی در پروژهٔ شما میتواند خوانایی بالایی ایجاد کند. اگر مثال بالا را بخواهیم با آرایهها بنویسیم، به این صورت خواهد بود؛ var programming_languages = ["C", "C++", "Java", "Rust", "R", "Javascript", "PHP", "Swift", "Ruby", "Perl", "Python", "HTML"] آیا با این روش میتوانید سریع به دادهٔ موردنظر خود دسترسی داشته باشید؟ مسلما خیر! چرا که به این صورت اگر بخواهید دادههای خود را تعریف کنید و از آنها استفاده کنید، وقت و انرژی زیادی از شما خواهد گرفت! پیدا کردن ایندکس ( به عنوان مثال R ) وقت و انرژی از شما خواهد گرفت. اما اگر با نوعهای شمارشی بنویسید، علاوه بر کدنویسی زیباتر و تمیزتر، دسترسی سریعتر و راحتتری هم خواهید داشت. به این مثال دقت کنید؛ enum Languages { case C case Java case Rust case R case Python case PHP case Javascript case HTML case Perl case Ruby case Swift } var language = Languages.Javascript switch language { case .C: print("C is programming language!") case .Java: print("Java is programming language!") case .Rust: print("Rust is programming language!") case .R: print("R is programming language!") case .Python: print("Python is programming language!") case .PHP: print("PHP is programming language!") case .Javascript: print("Javascript is programming language!") // Javascript is programming language! case .HTML: print("HTML is programming language!") case .Perl: print("Perl is programming language!") case .Ruby: print("Ruby is programming language!") case .Swift: print("Ruby is programming language!") } در مثال بالا مشاهده میکنید که شما میتوانید به راحتی با تعریف یک نوع شمارشی، به راحتی هرچه تمامتر به دادههای آن با استفاده از نام آنها دسترسی داشته باشید. در دستورات شرطی مثل switch دقت کنید که ابتدا باید مقدار دادهٔ مورد نظرتان از نوع شمارشی که تعریف کردهاید را به متغییر انتساب داده و سپس به عنوان یک مقدار به دستور switch بدهید تا بتواند آن را بررسی کند! چرا که در switch مقدار باید ثابت باشد نه متغییر! و سپس در بدنهٔ شرط، با استفاده از دات ( . ) و نام دادهٔ موردنظر در caseها ( case .HTML ) میتوانید دادهی ثابتی که در switch تعریف کردید را با مقادیر caseها مقایسه کنید و در نهایت خروجی متناسب با آن را مشاهده کنید. امیدواریم که این جلسه مورد رضایت شما قرار گرفته باشد.
-
سید محمد عباسی شروع به دنبال کردن کامبیز اسدزاده کرد
-
آموزش زبان برنامهنویسی سوئیفت - جلسه نُهم مواردی که در این جلسه یاد خواهید گرفت: توابع ( Functions ) توابع چیستند؟ این چیزی را که میگوییم، چند لحظه تصور کنید و دوباره به خواندن این مطلب ادامه دهید! فرض کنید پروژهای را شروع کردید و در بخشی از پروژهی خودتان، متوجهی این شدید، بخشی از کد نیاز به تکرار در جای دیگر دارد... از نظر شما، این کار تکرار کُد؛ بیهوده و بیمعنی است. پس راهحل چیست؟ توابع، یکی از روشهای جلوگیری از این کارهاست! گفتیم یکی از روشها، چرا که روش دیگری نیز وجود دارد که عهدهدار آن کلاسها هستند. توابع به شما کمک میکنند که کدهای کمتری بنویسید و بیشتر استفاده کنید! شما با یکبار نوشتن یک قطعه کد، میتوانید در ادامهی پروژهی بینهایت از آن قطعه کد استفاده کنید! این همان کاریست که توابع انجام میدهند. از جلمه مزایای استفاده از توابع میتوان به موارد زیر اشاره کرد؛ جلوگیری از تکرار کدها یا همان قابلیت استفاده مجدد که میتوانیم یکبار یک تابع را نوشته و چندین بار در جاهای مختلف برنامه از آن استفاده کنیم سرعت بیشتر جدا نگهداشتن بخشهای مختلف یک برنامه ( از لحاظ منطقی و همچنین از دید برنامهنویسی کاری منطقی نیست که یک پروژه را به بخشهای مختلفی تقسیم نکنیم و همهی کارها را به یک بخش محول کنیم ) خوانایی بیشتر برنامه خطایابی آسانتر میشود و مواردی دیگر ... البته مواقعی هم هستند که توابع باعث میشوند که سرعت اجرای برنامه کاهش پیدا کند! مانند موقعی که شما به توابع پارامتر میدهید، و در یک فراخوانی ( Calling ) آرگومانهای خود را به آن ارسال میکنید، سرعت اجرا پایین میآید، اما موقعی که کدها را مستقیما مینویسید، حافظه درگیر فراخوانی و گرفتن ورودی نمیشود و مستقیم، روی فراخوانی و اجرای کدها تمرکز میکند. نحوهی تعریف یک تابع ابتدا به نحوهی تعریف یک تابع میپردازیم و در ادامه هر بخش را توضیح خواهیم داد؛ func FunctionName ( Parameters ) -> ReturnType { // Statements return parameters } همان طور که مشاهده میکنید، تعریف کلی یک تابع در سوئیفت به این شکل است. از کلمهی کلیدی func شروع میکنیم. این کلمهی کلید که کوتاه شدهی ( function ) به معنای تابع است، به کامپایلر اطلاع میدهد که برنامهنویس میخواهد یک تابع تعریف کند! درواقع این نشانگر تعریف یک تابع است. بعد از این کلمهی کلید باید یک نام برای تابع خودتان انتخاب کنید. بدون نام شما چطور میخواهید به تابع خود دسترسی داشته باشید؟ در انتخاب نام آزاد هستید، اما علاوه بر رعایت نکات نامگذاری توابع، نام تابع شما باید نمایانگر کاری است که تابع شما قرار است انجام دهد. بعد از نام، شما باید در بین دو پرانتز () پارامترهای ( Parameters ) را مشخص کنید! پارامترها، متغیرهایی هستند که در هنگام تعریف تابع، مشخص میشوند و برای گرفتن مقداری خاص از کاربر استفاده میشوند. بعد از مشخص کردن پارامترها، باید نوع برگشتی ( ReturnType ) را مشخص کنید. فرض کنید میخواهید عمل فیلتر را روی تصویر انجام دهید! اگر بخواهید بعد از اعمال فیلتر روی تصویر توسط تابع، تصویر فیلترشده را در اختیار داشته باشید، نیاز خواهید داشت که آن را در قالب خاصی به تابع برگردانید! و اگر فقط تصویر فیلترشده را خواستید نمایش بدهید، به طور مستقیم و بدون نوع برگشتی میتوانید اینکار را انجام دهید. منظور از قالب خاص، همان نوع دادهای است که به تابع برگردانده میشود. در انتها، شما دربین دو آکولاد {}، میتوایند دستورات خود را بنویسید. فراموش نکنید که در آخر دستورات، باید return parameters را بنوسید! چرا که شما اگر نوع برگشتی را مشخص کرده باشید، باید مقداری هم برگشت دهید و اینکار با استفاده از این دستور امکانپذیر است. البته بهجای parameters باید دادهی مرتبط با نوع برگشتی را بنویسید. توضیحات کافیست؛ بیاید یک مثال عملی را با هم ببینیم؛ func getWebSite(website_name: String) -> String { let platform_name_and_website_name = "www.fanoox.com + " + first_name = " :) -> Perfect!" return platform_name_and_website_name } print(getWebSite(website_name: "www.iostream.ir") // www.fanoox.com + www.iostream.ir = :) -> Perfect همانطور که مشاهده کردید، شما یک اسم برای پارامتر انتخاب میکنید و به دنبال آن نوع داده را انتخاب میکنید. مانند؛ website_name: String و نوع برگشتی را هم که ملاحضه میکنید، با علامت <- و سپس نوع دادهی موردنظر ( در این مثال؛ String ) مشخص میکنید. بعد از آن شما میتوانید در بین دو آکولاد باز و بسته {}، کدهای خود را در درون آنها بنویسید و در آخر فراموش نکنید باید یک مقداری را برگشت دهید که با دستور return و مقدار برگشتی ( در این مثال؛ platform_name_and_website_name ) را تعیین کنید. دقت کنید که مقداری را که برگشت میدهید باید با نوع دادهای که در تعریف تابع مشخص شده است، یکسان باشد. برای فراخوانی یا همان صدا زدن تابع، همانطور که میبینید، باید فقط اسم تابع را بیاورید و بعد از آن اگر پارمتری الزامی بود، به آن بدهید. نام پارارمتر را هم باید حتما با نام باشد! ( "website_name: "www.iostream.ir ) که غیر از این باشد، کامپایلر از شما خطا خواهد گرفت. همچنین شما میتوانید یک تابع بدون پارامتر و با نوع برگشتی داشته باشید و یا برعکس! یعنی بدون پارامتر و نوع برگشتی. ابتدا یک تابع با نوع برگشتی و بدون پارامتر مثال خواهیم زد؛ func getWebSite() -> String { let platform_name = "www.fanoox.com -> :) -> Perfect!" return platform_name } print(setWebSite()) // www.fanoox.com -> :) -> Perfect همانطور که مشاهده کردید، ما میتوانیم یک تابع بدون پارامتر و در عین حال با نوع برگشتی داشته باشیم. در مقابل اگر هیچکدام از این موارد را نخواهیم؛ یعنی بدون پارارمتر و نوع برگشتی، به این صورت عمل خواهیم کرد؛ func getWebSite() { print("www.fanoox.com -> :) -> Perfect!") } getWebSite() // www.fanoox.com -> :) -> Perfect مشاهده میکنید که در قطعه کد بالا نه خبری از نوع برگشتی است و نه پارارمتر و شما به طور مستقیم بر روی دادهها کار میکنید. پارامترهای چندگانه فرض کنید میخواهید یک ماشین حساب طراحی و کدنویسی کنید! اگر بخواهید از توابع استفاده کنید، نیاز به این خواهید داشت که دو عدد به همراه یک آپریتر ( Operator ) به تابع ارسال کنید. در این صورت ما از پارامترهای چندگانه استفاده میکنیم. یعنی شما میتوانید تا بینهایت، پارارمتر در هنگام تعریف تابع، بنویسید. بیاید یک ماشین حساب کوچک، با هم طراحی کنیم؛ func Calculator(number_one: Double, number_two: Double, operator_ch: Character) -> Double { if operator_ch == "+" { return number_one + number_two } else if operator_ch == "-" { return number_one - number_two } else if operator_ch == "*" { return number_one * number_two } else if operator_ch == "/" { return number_one / number_two } else { return 0 } } print(Calculator(number_one: 10, number_two: 30, operator_ch: "+")) // 40 // 40 + 30 = Chelsea print(Calculator(number_one: 10, number_two: 20, operator_ch: "+")) // 30 به همین سادگی ما توانسیتم یک ماشین حساب کوچک طراحی کنیم! شما میتوانید حتی با اضافه کردن ویژگیهای جدیدتر، آن را گسترش دهید. اما نکتهی مهمتر از آن، پارارمترهای چندگانه هستند که مشاهده کردید. ما در هنگام تعریف تابع ماشینحساب، از سه پارارمتر استفاده کردیم! دو عدد و یک کارکتر. دو عدد که کاربر وارد کرده و کارکتر هم همان یک از ۴ آپریتر (+,-,/,* ) هستند که درواقع چهار عمل اصلی در محاسبات ریاضی را انجام میدهند. همچنین شما میتوانستید بدون اینکه بخواهید نوع برگشتی را مشخص کنید، مستقیم نتیجه را نمایش دهید؛ func Calculator(number_one: Double, number_two: Double, operator_ch: Character) { if operator_ch == "+" { print(number_one + number_two) } else if operator_ch == "-" { print(number_one - number_two) } else if operator_ch == "*" { print(number_one * number_two) } else if operator_ch == "/" { print(number_one / number_two) } else { print(0) } } Calculator(number_one: 10, number_two: 30, operator_ch: "+")) // 40 // 40 + 30 = Chelsea Calculator(number_one: 10, number_two: 20, operator_ch: "+")) // 30 میتوانید تا بینهایت پارامتر اضافه کنید، اما دقت کنید که اینکار باعث اشغال منابع از حافظه میشود، پس به تعداد مورد نیاز، پارامتر اضافه کنید. نام پارامترها و برچسبهای آرگومانها در حالت پیشفرض اگر تابعی را تعریف کنید و پارامتری را هم برای آن مشخص کنید، در هنگام فراخوانی ( Calling ) موظف هستید که اسم نام متغییر در پارامتر که برچسب خوانده میشود را هم بیاورید و سپس مقدار را در مقابل آن بنویسید؛ func getFirstName(first_name: String) -> String{ return "FirstName is : \(first_name)" } func getLastName(last_name: String) -> String { return "LastName is : \(last_name)" } func getStyleMe() -> String{ return " ): + :) with code = :) -> Perfect! " } print(getFirstName(first_name: "Mohammad"), getLastName(last_name: " Abasi"), getStyleMe())) // Mohammad Abasi ): + :) with code = :) -> Perfect! همانطور که مشاهده کردید، در هنگام فراخوانی موظف به نوشتن برچسب نام متغییرها در هنگام تعریف تابع نیز میباشید! ( در این مثال، first_name و last_name ) البته این حالت پیشفرض حالت سوئیفت است و شما میتوانید از این حالت پیشفرض استفاده نکنید ( در ادامه بیشتر توضیح خواهیم داد ) و در این مورد سوئیفت، کاملا دست شما را باز نگه داشته است. اگر بخواهید از دو برچسب در پارامترها استفاده کنید و یکی از برچسبها فقط نقش گرفتن مقدار را داشته باشد، به این صورت میتوانید عمل کنید؛ func getFullName(name first_name: String, last last_name: String) -> String { return "FirstName is : \(first_name) and LastName is : \(last_name)" } print(getFullName(name: "Mohammad", last: "Abasi")) // FirstName is : Mohammad and LastName is : Abasi برچسبهای اولیه ( name, name ) همان نقش پیشفرض را برای تابع بازی میکند و مقدارهای رشتهای Mohammad و Abasi در برچسبهای last_name و first_name ذخیره میشوند. ا گر نخواستید از برچسبها استفاده کنید و درواقع آنها را مزاحم دانستید؛ میتوانید از علامت آنِدرلاین ( ـ ) برای این منظور استفاده کنید؛ func getFullName(_ first_name: String, _ last_name: String) -> String { return "FirstName is : \(first_name) and LastName is : \(last_name)" } print(getFullName("Mohammad", "Abasi")) // FirstName is : Mohammad and LastName is : Abasi دقت کنید که حتما شما باید یک نام یا همان برچسب دوم برای ذخیره شدن مقدار آرگومان ( در این مثال؛ first_name, last_name ) بنویسید. همانطور هم که ملاحضه کردید، در هنگام فراخوانی تابع، ما دیگر از برچسب استفاده نکردیم! بلکه با گذاشتن علامت آندِرلاین ( ـ ) کامپایلر برچسبها را نادیده گرفته است. پارامترهای پیشفرض شما میتوانید از مقادیر پیشفرض برای توابع خود استفاده کنید! اگر تابعی را که تعریف میکنید، مطمعن نیستید که کاربر مقداری را وارد میکند یا نه، میتوانید از مقادیر پیشفرض موردنظر خود برای این منظور استفاده کنید؛ func getFullName(_ first_name: String = "Mohammad", _ last_name: String = "Abasi") -> String { return first_name + " " + last_name } print(getFullName()) // Mohammad Abasi print(getFullName("Mehdi")) // Mehdi Abasi print(getFullName("Hamed", "Doosti")) // Hamed Doosti همانطور که مشاهده کردید، شما میتوانید از یک یا چند مقدار ( بستگی به نیاز ) به صورت پیشفرض استفاده کنید که اگر احیانا کاربر، مقداری را وارد نکرد، کامپایلر از مقدار پیشفرض که تعیین کردید، استفاده میکند. در فراخوانی اول مشاهده میکنید که چون برای هر دو پارامتر first_name و last_name مقداری مشخص تعیین کردیم، بدون هیچ مسئلهای، خروجی برای ما نمایش داد میشود و در فراخوانیهای ("getFullName("Mehdi نگران پارامتر دوم نیستیم! چرا که مقدار پیشفرض Abasi را دارد. و همچنین ("getFullName("Hamed", "Doosti هم مقادیر آن جایگزین با مقادیر Mohammad و Abasi میشود. پارامترهای متغییر ( Variadic Parameters ) شاید با خود بگویید؛ پارامترهای متغییر دیگر چیستند؟! در اکثر مواقع ما میخواهیم فقط و فقط با یک پارامتر در یک تابع، تا بینهایت بتوانیم هنگام فراخوانی، مقادیر ارسال کنیم! در برخی از زبانهای برنامهنویسی این امکان فراهم شده است و سوئیفت هم یکی از این زبانهاست. اگر یک تابع داشته باشید که نام مشتریان را دریافت کند و آنها را در دیتابیس ( پایگاه داده ) ذخیره کند، در این صورت شما نمیتوانید از هزاران پارامتر برای این منظور استفاده کنید و کاری غیر منطقی است. بنابراین با استفاده از الگوی زیر، شما میتوانید با یک پارامتر، تا بینهایت نام مشتری به تابع ارسال کنید؛ var database = Array<String>() func storeCustomers(_ customer: String ... ) { database = customer } func getCustomer(_ index: Int = 0) -> String { return database[index] } storeCustomers("Mohammad", "Mehdi", "Ahamad", "Nahid", "Zhara", "Ali", "Hamed", "Daryoos", "Karim") print(getCustomer(1)) همانطور که مشاهده میکنید، در تابع storeCustomers پارامتر ... customer: String _ استفاده کردیم که بیانگر تابعی با پارامترهای متغییر است! این پارامتر همانند یک آرایه عمل میکنید و تنها تفاوت آن غیرقابل تغییر بودن و به اصطلاح فقط خواندنی ( Read-Only ) است. اگر سعی کنی که customer را تغییر دهید، با این خطا مواجه خواهد شد؛ cannot assign to value: 'customer' is a 'let' constant، که نشانگر آن است، این آرایه ( در این مثال؛ customer ) یک ثابت یا همان let است و قابل تغییر نیست. سه نقطهای ( ... ) که مشاهده میکنید، به کامپایلر این پیغام را میرساند که این تابع قرار است بیش از یک مقدار دریافت کند و یا همان مقادیر متغییر! پس آن را فراموش نکنید. در قطعه کد بالا، ما یک شبیهسازی ذخیره و بازیابی نام کاربر را انجام دادهایم که شما میتوانید با خلاقیت خودتان، چیزی بهتر و خارقالعادهتر بنویسید! پس با این روش میتوانید پارامترهای متغییر ارسال کنید و نگران این نباشید که هزاران پارامتر تعریف کنید؛ به این نکته هم دقت کنید که حتما حتما در این نوع تعریف تابع، باید از آندِرلاین ( - ) استفاده کنیم در غیر اینصورت با خطای کامپایلر مواجه خواهید شد. نکته شما نمیتوانید بیش از یک variadic parameters در تابع خود داشته باشید! فقط و فقط مجاز به تعریف یک variadic parameter هستید. پارامتر با ارجاع اگر شما یک متغییر خارج از تابع داشته باشید و بخواهید همان متغییر را به تابع بفرستید، عملا مقدار کُپی شده است! این یعنی اینکه اگر تغییری در متغییر داخل تابع که به عنوان متغییر داخلی ( Local ) شناخته میشود؛ صورت گیرد، متغییر سراسری ( Global ) هیچ تغییری نمیکند! چرا که فقط مقدار کپی شده است نه ارجاع! اگر بخواهیم همان متغییری را که به تابع ارسال میکنیم، همزمان با تغییر متغییر در تابع، تغییر کند، به این صورت عمل خواهیم کرد؛ var first_name : String = "Mohammad" func Local(_ first_name: inout String) -> String{ first_name = "Mehdi" return first_name // Current value } func Global() -> String { return first_name // Value has changed } print(Local(&first_name)) // Mehdi print(Global()) // Mehdi همانطور که مشاهده کردید، ابتدا یک متغییر سراسری ( "var first_name : String = "Mohammad ) تعریف کرده و سپس دو تابع به نامهای Local و Global ایجاد کردیم. اولین تابع یعنی؛ Local برای دریافت مقدار از طرف کاربر است و اگر توجه کرده باشید ما در پارامتر تابع از کلمهی کلید inout استفاده کردهایم! این کلمهی کلیدی برای دریافت مقدار با ارجاع است و حتما باید آن را بعد از نام پارامتر و دو نقطه ( : ) بیاورید و در نهایت نوع داده را مشخص کنید. در مقابل تابع Global است که مقدار تغییر داده شدهی متغییر سراسری را تغییر میدهد ( همان متغییر که بالاتر از تمام توابع نوشته شده است ). در هنگام فراخوانی تابع دقت داشته باشید که اگر از ارجاع ( کلمهی کلید inout ) استفاده کرده باشید، باید حتما از آپریتر & قبل از فرستادن متغییر به تابع استفاده کنید! چرا که قرار است آدرس متغییر را به تابع ارسال کند و در این صورت است که میتوانیم عمل ارجاع و تغییر متغیر سراسری را انجام دهیم. هنگامی که شما متغییر first_name& را به این شکل به تابع ارسال میکنید، درواقع آدرس را ارسال میکنید و آدرس حافظهی متغیر داخل تابع، با متغییر سراسری یکی است! وقتی متغییر داخلی تغییر کند، متغییر سراسری هم تغییر میکند. در فراخوانی توابع هم مشاهده میکنید که علاوه بر اینکه متغییر داخلی مقدار تغییر کرده ( تابع Local )، متغییر سراسری هم مقدارش تغییر کرده است ( تابع Global ). بنابراین ما میتوانیم به این صورت عمل ارجاع و تغییر متغییر از بیرون تابع را انجام دهیم. نکته شما نمیتوانید از مقادیر پیشفرض در این نوع تعریف تابع استفاده کنید و همچنین هم مجاز به استفاده از مقادیر متغییر ( variadic parameter ) نخواهید بود. استفاده از نوعهای تابعی سوئیفت، قابلیتهای جالب و در عین حال ساده دارد! یکی از این قابلیتها نوع تابعی است! ما اگر میخواستیم یک متغییر معمولی تعریف کنیم، به این شکل عمل میکردیم؛ var number : Double = 20.0 حال ما میتوانیم یک متغییر با حالت تابع داشته باشیم! به این مثال دقت کنید؛ func addition(number_one: Double, number_two: Double) -> Double { return number_one + number_two } let _addition_function : (Double, Double) -> Double = addition print(_addition_function(10.0,10.0)) // 20.0 احتمالا شما هم مثل عاشق پیچیدگی هستید! اینطور نیست؟! در قطعه کد بالا تابع را تعریف کردهایم که عملا کاری با آن نداریم! ما به متغییر تابعیمان _addition_function کار خواهیم داشت و میخواهیم آن را موشکافی کنیم! در ابتدا شما میتوانید از کلمهی کلید let و یا var استفاده کنید و سپس با دو نقطعه ( : ) که به آن کالُن هم گفته میشود، در بین دو پرانتز () نوع دادههایی را که در پارامتر تابع تعریف کردید، مینویسید. و سپس همانند نوع برگشتی در تابع ( Double <- ) باید بعد از پرانتز بسته شده ( Double, Double ) آن را بنوسید و سپس تابعی را که از قبل تعریف کردیم به آن بدهیم! توجه کنید فقط و فقط نام تابع کافیست و نیازی به پرانتز نیست. الان شما متغییر با حالت تابعماننده دارید و میتوانید از آن استفاده کنید. هنگامی که متغییر خود را فراخوانی میکنید، باید آرگومانهای الزامی را به آن بدهید؛ همانند مثال بالا ( (addition_function(10.0, 10.0 ). نکتهی دیگر که وجود دارد این است که دیگر نیازی نیست، نام پارامترها را هم برای مقداردهی بیاورید! در صورتی که با تعریف یک تابع معمولی، شما موظف بودید که نام پارامترها هم برای مقداردهی بنویسید. توابع تودرتو ( Nested Functions ) ما میتوانیم توابعی تودرتو داشته باشیم که عملیات خاصی را برای ما انجام دهند؛ func NestedFunctions(_ name: String) -> (String) -> String{ func lastNameOne(last_name_one: String) -> String { return "Last Name is One : \(last_name_one)"} func lastNameTwo(last_name_two: String) -> String { return "Last Name is Two : \(last_name_two)"} func Error(error: String ) -> String {return "Error is : \(error)"} if name == "Mohammad" { return lastNameOne } else if name == "Mehdi" { return lastNameTwo } else { return Error } } print(NestedFunctions("Mohammad")("Abasi")) // or var _function = NestedFunctions("Mehdi") print(_function("Abasi")) let funct = NestedFunctions("Hamed") print(funct("This is not name!")) در قطعه کد بالا، ابتدا ما یک تابع به NestedFunctions تعریف کرده و سپس یک پارامتر ( name : String ـ ) ایجاد کردیم. نوعهای برگشتی را شاید تعجب کرده باشید! اما کاملا ساده هستند! اولین آنها ( ( String ) <- ) اصلا نوع برگشتی نیست! بلکه این نوعها، برای پارامترهای توابع داخلی هستند ( lastNameOne, lastNameTwo ) شما میتوانید تا بینهایت پارامتر اضافه کنید ( دقت کنید به همان تعداد پارامتر که در تابع خارجی برای توابع داخلی اضافه میکنید، به همان تعداد پارامتر هم باید برای خود توابع بنویسید ).به همین خاطر هم است که با درون پرانتز این نوع دادهها را نوشتیم تا با نوع برگشتی، اختلالی ایجاد نکند. و در نهایت نوع برگشتی ( String <- ) برای برگرداندن مقدار برگشتی توابع داخلی است! در واقع کار تابع NestedFunctions برگرداندن یک تابع است! در بدنهی تابع NestedFunction دو تابع داخلی تعریف کردیم ( lastNameOne, lastNameTwo ) که البته بسته به کار شما، تابع میتواند در یک خط یا چند خط نوشته شود. اگر به دقت نگاه کرده باشید میبییند که توابع داخلی فقط یک پارامتر دارند که یکسان با پارامتر در تابع NestedFunctions است. بنابراین اگر خواستید پارامترهای بیشتری اضافه کنید، باید هر دو پارامترها را تغییر دهید! به این صورت؛ func NestedFunctions(_ name: String) -> (String,Int) -> String{ func lastNameOne(last_name_one: String, age: Int) -> String { return "Last Name is One : \(last_name_one) and Age is : \(age)"} func lastNameTwo(last_name_two: String, age: Int) -> String { return "Last Name is Two : \(last_name_two) and Age is : \(age)"} func Error(error: String, status_code: Int) -> String {return "Error is : \(error) and Status of code : \(status_code)"} if name == "Mohammad" { return lastNameOne } else if name == "Mehdi" { return lastNameTwo } else { return Error } } print(NestedFunctions("Mohammad")("Abasi", 20)) // or var function = NestedFunctions("Mehdi") print(function("Abasi", 18)) let funct = NestedFunctions("Hamed") print(funct("This is not name!",440)) /* Last Name is One : Abasi and Age is : 20 Last Name is Two : Abasi and Age is : 18 Error is : This is not name! and Status of code : 440 */ همانطور که مشاهده کردید، میتوانید پارامترهای موردنیازتان را هماهنگ با پارامترهای توابع داخلی تعریف کنید. مورد بعد نوع برگشتی تابع داخلی است که کاملا باید با نوع برگشتی مشخص شده در تابع خارجی مطابقت داشته باشد و در نهایت در بدنهی تابع داخلی میتوانید دستورات خود را بنویسید و در آخر دادهیم موردنظر را با استفاده از return برگردانید. در خطوط بعد دستورات شرطی را خواهیم داشت که بر اساس پارامتر name کار میکنند! اگر مقدار name برابر با رشتهی Mohammad باشد، تابع lastNameOne را برمیگردانیم و اگر مقدار آن برابر با رشتهی Mehdi باشد، تابع lastNameTwo را برمیگردانیم. اگر مقدار name با هیچکدام از رشتههای گفته شده، تطابق نداشته باشد، تابع Error برگشت داده میشود. دقت کنید که برای برگشت یک تابع، فقط نام آن را میآوریم و نیازی به پرانتز نیست. برای فراخوانی هم شما به دو صورت میتوانید عمل کنید؛ از آنجا که مقداری که NestedFunctions برمیگرداند، یک تابع است، پس باید به تابع داخلی هم دسترسی داشته باشیم! به دو روش میتوانیم اینکار را انجام بدهیم؛ روش اول به این شکل است؛ print(NestedFunctions("Mohammad")("Abasi", 20)) یعنی همزمان با دادن پارامتر به NestedFunctions، همان لحظه به صورتی که میبینید، در بین دو پرانتز () آرگومانتهای تابع داخلی را هم بدهید (Abasi", 20" ). یا یک متغییر تعریف کرده و تابع داخلی را از NestedFunctions گرفته و به متغییر انتساب دهید؛ var function = NestedFunctions("Mehdi") print(function("Abasi", 18)) شما به این دو صورت میتوانید به توابع داخلی خودتان دسترسی داشته باشید. امیدواریم که این جلسه مورد رضایت شما قرار گرفته باشد.
-
آموزش زبان برنامهنویسی سوئیفت - جلسه نُهم مواردی که در این جلسه یاد خواهید گرفت: تاپلها ( Tuples ) تاپِلها چیستند؟ تاپلها گروهی از دادهها هستند که از دادههای مختلفی تشکیل شدند و درواقع ترکیبی از مقادیر هستند! در این نوع، برای دسترسی به مقادیر، از کلید/مقدار ( key/value ) استفاده میکنیم. این نوع از مجموعهها، میتوانند هر دادهای را در خود ذخیره کنند و نیازی به تعریف نوع داده برای آنها نیست. به زبان ساده؛ تاپلها از اینکه شما بخواهید برای هر نوع دادهای یک کلاس جداگانه تعیین کنید ( مانند Set )، جلوگیری میکند و مجموعهای از دادههای مختلف را برای شما فقط در یک متغییر ذخیره میکند و در ادامه میتوانید از آن استفاده کنید. تعریف یک تاپل برای اینکار، ابتدا یک متغییر تعریف کرده ( کلمات کلید let, var ) یک نام انتخاب کرده و سپس در بین دو پرانتز () دادههای خود را با کاما ( , ) از هم جدا میکنید؛ let ـfamily = ("Mohammad", 20, 1378, "Esfahan-Felavarjan") همچنین شما میتوانید بخشی از دادههای یک تاپل را در یک متغییر دیگر ذخیره کنید و یا به اصطلاح بُرش بزنید! به این مثال دقت کنید؛ let ـfamily = ("Mohammad", 20, 1378, "Esfahan-Felavarjan") let (first_name, age, birthday, _) = family print("FirstName is : \(ـfirst_name)") // FirstName is : Mohammad اگر دقت کرده باشید، در آخرین تعریف یک متغییر، بجای نام ما از آندِرلاین ( ـ ) استفاده کردیم! دلیل آن هم این است که اگر مقداری را نخواهیم، از این علامت استفاده میکنیم. به عنوان مثال؛ مقدار رشتهای Esfahan-Felavarjan را نادیده گرفتیم و با علامت ( ـ ) گفتیم که مقدار آخر را نادیده بگیر! اگر اینکار را نکنید، خروجی به شما نمایش داده نخواهد شد و با خطای کامپایلر روبرو خواهید شد. نکته دقت داشته باشید که شما اگر بخواهید بخشی از دادههای تاپل را داشته باشید و در یک متغییر ذخیره کنید، دو راه بیشتر ندارید؛ یا اینکه همهی دادهها را دریافت کنید، مانند مثال زیر؛ let ـfamily = ("Mohammad", 20, 1378, "Esfahan-Felavarjan") let (first_name, age, birthday, address) = family print("FirstName is : \(ـfirst_name)") // FirstName is : Mohammad یا اینکه با علامت ( ـ )، هر کدام از دادهها را که مدنظر شما نبود، نادیده گرفته و در نتیجه ذخیره نکنید؛ let ـfamily = ("Mohammad", 20, 1378, "Esfahan-Felavarjan") let (first_name, ـ , birthday, ـ) = family print("FirstName is : \(ـfirst_name)") // FirstName is : Mohammad اما دقت داشته باشید که شما به هیچوجه نمیتوانید با اختیار خود یکی از مقادیر را نادیده گرفته ( متغییر برای آن در نظر نگیرید ) و یا اینکه از علامت گفته شده، استفاده نکنید! شما به هر حال باید از یکی از این دو روش استفاده کنید. دسترسی به اعضای با استفاده از شماره موقعیت ( Index ) اینکار به صورتی جذاب انجام میشود! در این نوع از دسترسی، براکت ( [] ) خبری نخواهد بود و شما فقط با آوردن موقعیت ( Index ) میتوانید به مقدار تاپل دسترسی داشته باشید؛ let ـfamily = ("Mohammad", 20, 1378, "Esfahan-Felavarjan") print("FirstName is : \(_family.0)") // FirstName is : Mohammad print("Age is : \(_family.1)") // Age is : 20 همانطور که مشاهده کردید، با آوردن شماره موقعیت، میتوانید به مقدار آن دسترسی داشته باشید. دسترسی به اعضای با استفاده از نام شما همچنین میتوانید با استفاده از نامی که در ابتدای تعریف یک تاپل استفاده میکنید، با همان نام، به اعضای آن دسترسی داشته باشید؛ let ـfamily = (first_name: "Mohammad", age: 20, birthday: 1378, address: "Esfahan-Felavarjan") print("FirstName is : \(_family.first_name)") // FirstName is : Mohammad print("Age is : \(_family.age)") // Age is : 20 همانطور که مشاهده کردید، شما میتوانید برای مقادیر خود نام هم تعیین کنید و در ادامه با استفاده از همان نام، به مقدار آن دسترسی داشته باشید ( همانند دیکشنری ). بنابراین اگر در جایی از پروژهی خود نیاز به مقدارهای مختلفی داشتید و نخواستید که از کلاسها و نوعهای دادهی متفاوت استفاده کنید، میتوانید از تاپلها برای این منظور استفاده کنید. امیدواریم که از این جلسه مورد رضایت شما قرار گرفته باشد.
-
آموزش زبان برنامهنویسی سوئیفت - جلسه هشتم مواردی که در این جلسه یاد خواهید گرفت: دیکشنری ( Dictionary ) دیشکنریها چیستند؟ به طور ساده و خلاصه؛ یکی از نوعهای مجموعه است که مقادیر یا همان دادهها را به صورت کلید/مقدار ( key/value ) ذخیره میکند و همچنین نامرتب است و دادههای تکراری را فقط یکبار مورد ذخیره! اینکار به شدت میتواند به برنامهنویس کمک کند تا راحتتر، بهتر و سریعتر به دادههای خود از طریق کلید ( key ) دسترسی داشته باشد و همچنین کُدی خواناتر داشته باشد. برای اینکه این موضوع برای شما عزیزان شفافتر شود و بهتر بتوانید این موضوع را درک کنید، شروع به ایجاد دیکشنری خودمان خواهیم کرد و در ادامه، توضیحات لازم را ارائه خواهیم داد. برای ایجاد یک دیکشنری، به چهار صورت میتوانیم عمل کنیم؛ استفاده از کلاس Dictionary و سپاس در بین دو علامت <> کلید و مقدار خود را قرار میدهیم <Dictionary<Key, Value که البته باید در نظر داشته باشید، Key و Value نوع دادهایی هستند که باید قرار گیرند و بعدا مقداردهی بر اساس نوعهای داده خواهد بود نه مستقیما مقدادهی کنید! مانند؛ <Dictionary<String, Double تعریف یک متغییر و سپس استفاده از الگوی؛ ()[String : String ] استفاده از روش دوم با این تفاوت که شما میبایست، دیکشنری خود را همانند تعریف یک متغییر به صورت صریح بنویسید! شما میتوانید فقط از [] به صورت مستقیم استفاده کنید و دادهها را اضافه کنید، مانند؛ ["var products = ["www.fanoox.com : "MacBook Pro از اولین مورد شروع خواهیم کرد، پس به این شکل عمل میکنیم؛ var users_and_passwords= Dictionary<String, String>() users_and_passwords["Mohammad"] = "!#$#@%#$!#@$" users_and_passwords["Ali"] = ")+_)(*&^^%" users_and_passwords = ["Ali" : "_)(*&^%^&*", "Hamed" : "123456789%$#@!#$^%!$1009876!!$$%!$54321"] print(users_and_passwords) /* ["Ali" : "_)(*&^%^&*", "Hamed" : "123456789%$#@!#$^%!$1009876!!$$%!$54321" ] */ همانطور که مشاهده میکنید، یک متغییر تعریف کرده و سپس از کلاس Dictionary استفاده کردیم که در بین دو علامت <> ( بزرگتری و کوچکتری ) نوعهایی که میخواهیم از آنها در برنامهمان استفاده کنیم، به کار بردیم. شما میتوانید هم به تنهایی و هم گروهی، مقداردهی را شروع کنید! در قطعهکد بالا میبینید که خط ۲ و ۳، به صورت تَکی و خط ۴ به صورت گروهی مقداردهی شده است و در نهایت در خط ۵ آن را چاپ میکنیم. توجه داشته باشید که اگر در حالت گروهی بخواهید مقدادهی کنید، مقادیر قبلی از بین خواهند رفت! در حالی که اگر شما به صورت تکی مقداردهی کنید، این اتفاق نخواهد افتاد. نکته اگر به صورت تَکی بخواهید مقداردهی کنید، هیچ اتفاقی برای مقادیر دیگر نخواهد افتاد! اما اگر گروهی مقداردهی کنید، دادههای قبلی به کل پاک و دادههای جدید، قرار خواهند گرفت. دومین نوع تعریف بدون استفاده از کلاس است؛ var languages_and_framework = [String : String]() languages_and_framework["C++"] = "Qt Creator " languages_and_framework["PHP"] = "Laravel" print(languages_and_framework) /* ["C++" : "Qt Creator ", "PHP" : "Laravel"] */ در سومین حالت تعریف به این شکل عمل خواهیم کرد؛ var languages_and_framework : [String : String] = ["C++" : "Qt Creator", "Javascript" : "Angular.js"] print(languages_and_framework) /* ["C++" : "Qt Creator", "Javascript" : "Angular.js"] */ و در نهایت در حالت چهارم اگر بخواهیم دیکشنری خودمان را تعریف کنیم، به این صورت عمل میکنیم؛ var languages_and_framework = ["C++" : "QT Creator", "PHP" : "Laravel"] print(languages_and_framework) /* ["PHP" : "Laravel", "C++" : "Qt Creator"] نکته در تمامی این مثالها، وقتی دادهها را نمایش میدهیم، به صورت نامرتب نمایش داده خواهند شد! چرا که همان ابتدا گفتیم، دیکشنریها، نامرتب هستند و این مورد در خروجی دادهها هم صِدق میکند. نحوهی دسترسی به دادههای ما میتوانیم با استفاده کلید ( Key ) به دادههای مرتبط با آن دسترسی داشته باشیم! به این صورت که شما نام کلیدی را که از قبل انتخاب کردید، در بین دو براکت به همراه اسم دیکشنری خود آورده و سپس علامت تعجب ( ! ) را نوشته تا بتوانید مقدار مورد نظر را در دسترس داشته باشید! حتمالا با خود فکر میکنید که چرا علامت تعجب؟! اگر از جلسات قبل به خاطر داشته باشید، درمورد متغییرهای آپشِنال ( Optionals ) صحبت کردیم و گفتیم که برای دسترسی به مقادیر این نوع متغییرها باید از علامت ! استفاده کنیم. در دیکشنریها هم همین موضوع برقرار است و شما برای استفاده از دادههای آن باید آنها را از حالت آپشنال خارج کنید. به این مثال دقت کنید؛ let _name_and_age : [String : UInt] = ["Mohammad" : 20, "Hamed" : 30] print(_name_and_age["Mohammad"]!) // 20 اگر علامت ! را ننویسید، با خطای کامپایلر مواجه خواهید شد. به همین صورت تا هر چند مقدار را که میخواهید میتوانید به آن دسترسی داشته باشید. دقت کنید که اگر بخواهید یک مقدار خاص را در یک متغییر جداگانه ذخیره کنید، نیازی به علامت ! نخواهید داشت؛ let _name_and_age : [String : UInt] = ["Mohammad" : 20, "Hamed" : 30] let _age = _name_and_age["Mohammad"] print(_age["Mohammad"]!) // 20 اگر بخواهید متغییری که جداگانه تعریف کردید، نمایش دهید؛ آن موقع باید حتما از علامت تعجب ( ! ) استفاده کنید. اضافه کردن یک مقدار برای اضافه کردن یک مقدار، به همان صورتی که در بالا ( تکی اضافه کردن ) تعریف کردیم، استفاده میکنیم؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] numbers[40] = 50 print(numbers) /* [20 : 30, 10 : 20, 30 : 40, 40 : 50] */ بروزرسانی یک مقدار اگر بخواهیم دادههای خود را به روزرسانی ( Update ) کنیم، کافیست کلید را آورده و در مقابل، مقدار را اضافه کنیم؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] numbers[40] = 50 numbers[10] = 100 print(numbers) /* [20 : 30, 10 : 100, 30 : 40, 40 : 50] */ همانطور که مشاهده میکنید، کلید ما در این بروزرسانی، ۱۰ است است و مقدار ۱۰۰ را به آن اختصاص دادهایم! پس دیگر خبری از مقدار ۲۰ نخواهد بود. همچنین شما میتوانید از متد updateValue از کلاس دیکشنری استفاده کنید. این متد، علاوه بر اینکه مقدار فعلی از یک کلید را برمیگرداند، همزمان، مقدار جدید را در همان کلید قرار خواهد داد. این متد دو آرگومان ( Argumant ) دریافت میکند که به شرح زیر است؛ اولین آرگومان، مقدار جدید است. دومین آرگومان، کلید است. مقدار برگشتی که از این متد، آپشنال خواهد بود! به این مثال دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] numbers[40] = 50 numbers[10] = 100 if old_number = numbers.updateValue(200, forkey: 20){ print("Old the number : \(old_number)") // Old the number : 30 } print(numbers) /* [20 : 200, 10 : 100, 30 : 40, 40 : 50] */ در قطعه کد بالا مشاهده میکنید که از یک شرط استفاده کردیم و مقدار برگشتی از متد updateValue را به متغییر old_number اختصاص دادهایم. این مقدار از کلید آن یعنی forkey: 20 گرفته شده است. هنگام چاپ مقدار old_number نیاز به قرار دادن علامت تعجب ( ! ) نیست! اینکار در همانابتدا در شرط انجام شده است. و در نهایت، در خروجی نهایی کل دیکشنری همانطور که میبینید، مقدار ۲۰۰ به کلید ۲۰ اختصاص داده شده است. اگر کلید که شما در آرگومان دوم داده باشید، وجود نداشته باشد، پیغام Not Exit و دیکشنری نمایش داده میشود، بدون اینکه مقداری حذف شده باشد. حذف کلید و مقدار اگر بخواهید کلید و مقدار خود را در حذف کنید، از کلمهی کلید nil میتوانید استفاده کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] numbers[30] = nil print(numbers) /* [20 : 30, 10 : 20] */ مشاهده میکنید که کلید ۳۰ و مقدار ۴۰ هر دو حذف شدند. شاید با خودتان بگوید چرا کلید هم حذف شده است؟ به این دلیل که اگر مقداری برای کلید نباشد، خود کلید هم حذف خواهد شد؛ چون مقداری ندارد. شما میتوانید از متد removeValue نیز استفاده کنید! این متد یک آرگومان گرفته و کلید/مقدار را حذف میکند. آرگومانی که این متد دریافت میکند، کلید است و مقدار برگشتی آن، مقدار حذفشده و به صورت آپشنال است ( اگر کلید که شما در آرگومان دوم داده باشید، وجود نداشته باشد، پیغام Not Exit به همراه خود دیکشنری نمایش داده میشود. ) به این مثال دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] if remove_value = numbers.removeValue(forkey: 10){ print("Removed value : \(remove_value)") // Removed value : 20 } print(numbers) /* [20 : 30, 30 : 40] */ همانطور که مشاهده میکنید، مقدار ۲۰ نمایش داده شده که درواقع مقدار حذف شده است. و در آخر هم کل دیکشنری را نمایش میدهیم که کلید ۱۰ و مقدار ۲۰ حذف شدهاند. همچنین شما میتوانید با استفاده از متد removeAll همهی دادههای دیکشنری را حذف کنید! دقت کنید که فقط دادههای آن حذف خواهند شد نه خود دیکشنری! به این مثال دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] numbers.removeAll() print(numbers) // [:] همانطور که مشاهده کردید، فقط دادهها حذف شدند و خود دیکشنری هنوز در برنامهی ما وجود دارد؛ بنابراین در ادامه میتوانید دادههای خود را اضافه کنید. گردش در دیکشنری ( Iterating over a dictionary ) شما میتوانید با استفاده از حلقهی for کلیدها و مقدارها را دریافت کنید! هر کدام از این آیتمها ( کلید/مقدار ) یک تاپِل هستند. به این مثال دقت کنید تا بهتر این موضوع را متوجه شوید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] for (key, value) in numbers{ print("Key : \(key) and value : \(value)") } /* Key : 10 and value : 20 Key : 20 and value : 30 Key : 30 and value : 40 */ در قطعه کد بالا شما در حلقهی for در بین دو پرانتز () به دلخواه دو نام انتخاب کرده که نشان از کلید و مقدار است و در نهایت کلمهی کلید in را نوشته و دیکشنری را مینویسید. به دست آوردن کلیدها اگر بخواهید فقط و فقط کلیدهای یک دیکشنری را به دست آورید، میتوانید با استفاده از ویژگی ( Properties ) به نام keys در حلقهی for یا به تنهایی استفاده کنید. به این مثال دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] for key in numbers.keys{ print("Key : \(key)") } /* Key : 10 Key : 20 Key : 30 */ // Or print("Keys : \(numbers.keys)") // Output: Keys : [10,20,30] به دست آوردن مقدارها در مقابل شما میتوانید با استفاده از ویژگی values فقط و فقط به مقادیر دسترسی داشته باشید. به این مثال دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] for value in numbers.values{ print("Value : \(value)") } /* Value : 20 Value : 30 Value : 40 */ // Or print("Values : \(numbers.values)") // Output: Values : [20,30,40] مرتبسازی همانطور که میدانید و همان ابتدا هم گفتیم، دیکشنریها نوعی هستند که نامرتباند! یعن دادهها را به صورت تصادفی ( Random ) نمایش میدهند. اما ما در ادامه مثالی را ذکر خواهیم کرد که شما میتوانید، هم براساس کلید و هم مقدار، اقدام به مرتبسازی دادهها کنید. مرتبسازی بر اساس مقدار در این حالت ما با استفاده از ویژگی values و سپس متد sorted که همراه خودش دارد، براساس مقدار فقط دادهها را مرتب میکنیم؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] for sorted_by_value in numbers.values.sorted{ print("Sorted by value : \(sorted_by_value)") } /* Sorted by value : 20 Sorted by value : 30 Sorted by value : 40 */ نکته استفاده از دو حالت بالا صحیح است و اگر شما دو ویژگی values و keys را نیاورید، و فقط متد sorted را به همراه نام دیکشنری بنویسید، اشتباه خواهد بود و از طرف کامپایلر خطا دریافت میکنید. به مثال زیر که اشتباه است دقت کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] print(numbers.sorted()) // Error همانطور که مشاهده میکنید، استفاده از متد بدون ذکر یک از دو ویژگی values و keys از نظر کامپایلر بیمعنی است و در نتیجه خطا را صادر میکند. دسترسی به تعدا اعضای دیکشنری برای اینکه بتوانید به تعداد اعضای یک دیکشنری دسترسی داشته باشید، از ویژگی count میتوانید استفاده کنید؛ var numbers : [Int : Int] = [10 : 20, 20 : 30, 30 : 40] print("Count the numbers : \(numbers.count)") // Count the numbers : 3 دقت کنید که منظور از تعدا اعضا، هم کلید و هم مقدار نیست! بلکه یعنی یک کلید و یک مقدار میشود یک عضو! در قطعه کد بالا هم مشاهده میکنید که ما سه عضو داریم که در خروجی نمایش داده شده است. بررسی خالی بودن یا نبودن دیکشنری با استفاده از ویژگی isEmpty شما میتوانید، بررسی کنید که آیا دیکشنریتان خالی است یا نه؟! به این مثال دقت کنید؛ var numbers : [Int : Int] = [:] if numbers.isEmpty{ print("Dictionary is empty!") // Yes, it is Empty } else { print("Dictionary is not empty!") } با استفاده از [:] میتوانید در همان ابتدا اعلام کنید که دیکشنری شما خالی است. همانطور که در خروجی هم میبینید، خروجی برابر است با Dictionary is empty است. امیدواریم که این جلسه مورد رضایت شما قرار گرفته باشد.
-
آموزش زبان برنامهنویسی سوئیفت - جلسه هفتم مواردی که در این جلسه یاد خواهید گرفت: مجموعهها ( Collections ) مجموعهها در سوئیفت در واقع متغییرهایی هستند که بیشاز یک مقدار را نگهداری میکنند و هر کدام، هم طبق عملکردی که دارد، دادهها را ذخیره و در اختیار برنامهنویس میگذارد. منظور از هر کدام، ۴ نوع مجموعه است که در اینجا مشاهده خواهید کرد؛ آرایه ( Array ) سِت ( Set ) دیکشنری ( Dictionary ) تاپِل ( Tuple ) در جلسهی قبل، با اولین مجموعه؛ یعنی آرایهها به طور کامل آشنا شدید و در این جلسه با سِتها ( Sets ) کامل آشنا خواهید شد. به خاطر داشته باشید که هر کدام از این مجموعهها منحصر به فرد عمل کرده و هیچکدام شبیه هم نخواهند بود. سِتها ( Sets ) چیستند؟ سِتها کار شما را برای ذخیره کردن دادههای غیرتکراری راحت میکنند! یعنی اینکه شما به راحتی و بدون اینکه نگران باشید چه تعداد مقادیر تکراری دارید، میتوانید به روند توسعه پروژهی خودتان ادامه دهید و مابقی کار را به این یکی نوع از مجموعهها بسپارید. این در صورتی است که شما نمیخواهید دائما بررسی کنید که آیا دادههای تکراری دارید یا نه و با تعریف این نوع، خیالتان آسوده خواهد شد. همچنین دادههایی که در این نوع به نمایش درخواهند آمد، به صورت نامنظم هستند! یعنی اینکه اگر شما مقادیر خودتان را به صورت منظم اضافه کرده باشید، خروجی آن چیزی نیست که به صورت منظم خواسته باشید. در واقع میتوان گفت، Setها؛ دادههای غیرتکراری و نامنظم را در خود نگهداری میکنند. برای تعریف یک Set به این صورت عمل خواهیم کرد، میتوانیم به دو صورت عمل کنیم؛ استفاده از کلاس و تعیین نوع داده استفاده از کلاس بدون تعیین نوع داده به اولین مورد، یعنی استفاده از کلاس و تعیین نوع داده میپردازیم؛ پس به این صورت عمل خواهیم کرد؛ var setـvar = Set<String>() // Or any data type همانطور که مشاهده میکنید، ابتدا یک متغییر تعریف خواهید کرد و سپس نام کلاس Set را میآورید و در نهایت در بین <> نوع دادهی خود را مشخص میکنید و سپس پرانتز () را قرار میدهید. در حال حاضر، شما یک Set خالی خواهید داشت! چرا که هیچ دادهای برای آن در نظر نگرفتهاید. برای اینکار به شکل زیر عمل خواهیم کرد؛ var set_var = Set<String>() // Or any data type set_var.insert("www.iostream.ir") set_var.insert("www.fanoox.com") set_var.insert("Tegra CMS") set_var.insert("www.ModernCpp.ir") set_var.insert("Apple") set_var.insert("Google") set_var.insert("Apple") set_var.insert("Google") set_var.insert("Microsoft") // Iterator in the set_var for items in set_var { print("Items in the set_var collection : ", items) /* Items in the set_var collection : www.iostream.ir Items in the set_var collection : www.fanoox.com Items in the set_var collection : Tegra CMS Items in the set_var collection : www.ModernCpp.ir Items in the set_var collection : Apple Items in the set_var collection : Google Items in the set_var collection : Microsoft */ } برای اینکه بتوانیم دادهای یا مقداری را ذخیره کنیم، از متد insert استفاده میکنیم که در بالا هم مشاهده میکنید. اما نکتهای که به احتمال زیاد شما هم متوجه آن شدهاید، این است که ما دو بار مقدار Google و Apple را ذخیره کردهایم! اما همانطور که در تعریف Set گفتیم، در خروجی فقط یکبار این مقادیر نمایش داده میشوند، حتی اگر به تعداد زیاد بخواهید دادهی تکراری وارد کنید! چرا که این نوع ( Set ) فقط مقادیر غیرتکراری را ذخیره خواهد کرد. تعریف دیگر آن به این صورت است؛ var setـvar : Set = [1,2,3,4,5,6,7,8,9,10] print(set_var) // Output is [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] در این مورد، شما مانند تعیین نوع برای متغییر، نام کلاس Set را بعد از دو نقطه ( که به آن هم کالُن ( : ) گفته میشود ) آورده و سپس مانند یک آرایه، مقادیر و دادههای خودتان را در بین دو قُلاب [] مینویسید. برای نمایش دادن آن هم کافیست که نام آن را بیاورید، همانند تعریف بالا. این نکته را به یاد داشته باشید که کامپایلر، به صورت ضمنی ( Implicit ) نوع داده را تشخیص داده و نیازی به ذکر نوع داده نخواهید داشت. ویژگیها ( Properties ) و متدها به دست آوردن تعداد اعضا با استفاده از ویژگی count میتوانید به تعدا اعضای یک Set دسترسی داشته باشید؛ var set_var : Set = [1,2,3,4] print(set_var.count) // Output is 4 بررسی خالی بودن یا نبودن Set و همچنین اگر میخواهید خالی بودن یا نبودن را بررسی کنید، isEmpty این امکان را در اختیار شما قرار داده است؛ var set_var : Set = [1,2,3,4,5,6,7,8,9,10] if set_var.isEmpty { print("set_var is empty!") } else { print("set_var not empty") // This will run code } اضافه کردن عضو جدید در حالت عادی نمیتوانیم به Setهای خودمان عضوی یا دادهای اضافه کنیم! در تعریف دوم شما دیدید که ما به صورت مستقیم این کار را انجام دادیم، اما در ادامهی برنامه شاید نظرمان عضو شود و بخواهیم عضو را حذف و عضو دیگری را اضافه کنیم؛ برای این منظور از متد insert استفاده خواهیم کرد؛ var celebrities : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] celebrities.insert("Jeffrey Preston Bezos") celebrities.insert("Sergey Brin") celebrities.insert("Lawrence Lary Page") همانطور که مشاهده کردید، ما با استفاده از متد insert میتوانیم عضوهای جدیدی را اضافه کنیم. حذف یک عضو برای این کار ما از متد remove استفاده میکنیم؛ var celebrities : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] celebrities.remove("Steven Paul jobs") print(celebrities) // Output is ["William Henry Bill Gates lll", "Elon Reeve Musk"] این متد یک آرگومان دریافت خواهد کرد و همان عضوی است که میخواهید حذف شود. بررسی وجود داشتن یا نداشتن یک مقدار خاص از متد contains برای این منظور استفاده میکنیم؛ var celebrities : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] if celebrities.contains("Elon Reeve Musk") { print("Elon Reeve Musk is available in the celebrities") // This will run code } else { print("Elon Reeve Musk is'n available in the celebrities") } نکته متدهای کار با Set، با خود Set اصلی کاری نداشته و بسته به متد، یک Set جدید برگردانده میشود. گَردش در Set برای اینکه بتوانیم به تکتک اعضای یک Set دسترسی داشته باشیم، از حلقهی for استفاده میکنیم، به این کار گردش میگویند. در جلسهی قبل، توضیحی مختصر در این باره دادهایم که میتوانید مطالعه کنید. پس به گردش در Set به این صورت است؛ var celebrities : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] for items in celebrities { print("Celebrities : ", items) /* Celebrities : Steven Paul jobs Celebrities : William Henry Bill Gates lll Celebrities : Elon Reeve Musk */ } به همین سادگی، میتوانید بین عضوهای مختلف گردش کرده و پردازشهای لازم را بنابر نیاز انجام دهید. مرتبسازی در حالت پیشفرض، نوع Set هیچ مبنایی برای مرتبسازی ندارد و دادهها را به صورت تصادفی نمایش خواهد داد؛ در صورتی که بخواهید بر اساس ترتیب دادهها را نمایش دهید، میتوانید از متد sorted استفاده کنید؛ var celebrities : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] for items in celebrities.sorted { print("Sorted celebrities : ", items) /* Sorted celebrities : Elon Reeve Musk Sorted celebrities : Steven Paul jobs Sorted celebrities : William Henry Bill Gates lll */ } فقط توجه داشته باشید که این متد باید در حلقه مورد استفاده قرار گیرد. ایجاد یک Set جدید با ترکیب دو Set یا ( Union ) با استفده از متد union شما میتوانید یک Set کاملا جدید، ایجاد کنید؛ var celebrities_some_one : Set = ["Steven Paul jobs", "William Henry Bill Gates lll", "Elon Reeve Musk"] var celebrities_two_some : Set = ["Jeffrey Preston Bezos","Sergey Brin","Lawrence Lary Page"] var celebrities_final : Set = celebrities_some_one.union(celebrities_two_some) print(celebrities_final) ذخیره یک مقدار مشترک ( Intersection ) اگر دو Set داشته باشیم و یک مقدار در هر دو یکسان باشد، متد intersection میتواند همهی مقادیر دیگر را پاک کرده و فقط همان مقدار را در قالب یک Set جدیدی برگرداند؛ var numbers_one : Set = [1,6,3] var number_two : Set = [5,6,3] var number_final : Set = number_one.intersection(number_two) print(number_final) // Output is [6, 3] همانطور که مشاهده کردید، در خروجی مقدار 3 , 6 را خواهیم داشت، چرا که باقی مقدار تکراری نبوده و در نتیجه حذف خواهند شد. حذف مقادیر یک Set و مقادیر مشابه ( Subtracting ) اگر بخواهیم مقادیر یک Set را به طور کامل حذف کنیم و همچنین اگر مقداری تکراری وجود داشت، آن را هم حذف کرده و فقط Set اول را داشته باشیم، از متد subtracting استفاده خواهیم کرد؛ var numbers_one : Set = [1,6,3] var number_two : Set = [5,6,3] var number_final : Set = number_one.subtracting(number_two) print(number_final) // Output is [1] مشاهده میکنید که خروجی برابر ۱ است! چرا که Set اول فقط مقدار ۱ را دارد و مابقی مقادیر در Set اول و دوم تکرار هستن و در نهایت حذف خواهند شد. ایجاد یک Set جدید با مقادیر غیر تکراری ( SymmetricDiffernce ) در متد union شما مقادیر غیرتکراری را نخواهید داشت و در Set جدیدی که ساخته خواهد شد و یا به طور مستقیم در خروجی نمایش داده میشود، فقط یکبار مقادیر نمایش داده میشوند؛ اما با متد symmetricDifference شما مقادیر دو طرف Set را حذف خواهید کرد و فقط مقادیری که دیگر تکراری نیستند، نمایش داده میشود. اجازه بدهید با ذکر یک مثال، این موضوع را شفافتر کنیم؛ var numbers_one : Set = [1,6,3] var number_two : Set = [5,6,3] var number_final : Set = number_one.symmetricDiffernce(number_two) print(number_final) // Output is [1,5] همانطور که مشاهده میکنید، ما مقادیر ۳ و ۶ را نخواهیم داشت! چرا که در این متد، مقادیر تکراری هر دو Set حذف خواهند شد و دادههایی که تکراری نیستند، در یک Set جدید ایجاد میشوند. امیدواریم که این جلسه مورد رضایت شما عزیزان قرار گرفته باشد.
-
اگه برای کارهای ریزکاری باشه که بخواهیم دقیق باشیم، فک کنم Auto کاربرد داشته باشه که خروجی دیزاسمبل رو بخوایم ببینیم.
- 3 دیدگاه
-
- سیپلاسپلاس
- overloading
-
(و 5 مورد دیگر)
برچسب زده شده با :
-
ممنون از این مطلب ساده و روان. مورد آخر که Auto باشه رو به خوبی متوجه نشدم! البته متوجهی این نشدم که چرا باید نوع خروجی رو داشته باشیم؟
- 3 دیدگاه
-
- سیپلاسپلاس
- overloading
-
(و 5 مورد دیگر)
برچسب زده شده با :
-
آموزش زبان برنامهنویسی سوئیفت - جلسه ششم مواردی که در این جلسه یاد خواهید گرفت: آرایهها ( Arrays ) آرایهها چیستند؟ اگر شما یک بسته کِبریت را تصور کنید، حداقل تا 50 تا دانه کبریت داخل آن است! همهی آنها هم همه کبریت هستند نه چیز دیگر. البته میشود چیز دیگری هم گذاشت داخل آن اما در برنامهنویسی نمیتوانید همچین کَلکی را سوار کنید! ( در بعضی از زبانهای برنامهنویسی ). آرایهها در سوئیفت مجموعهای از مقادیر را داخل خودشان نگهداری میکنند و مانند یک متغییر میمانند با این تفاوت که یک متغییر معمولی یک مقدار رو میتواند ذخیره کند ولی متغییر آرایهای اینگونه نیست. به این دنبالهی عددی دقت کنید؛ 1,2,3,4,5,6,7,8,9,10 بهنظر شما میشود اینها را در یک متغییر معمولی ذخیره کرد؟ به طوری که هر کدام از عددها را که بخواهیم سریع به ما بدهد؟ مسلما خیر. تازه اگر شما بخواهید برای هر کدوم از این اعداد، یه متغییر جداگانه تعریف کنید؛استاندارد پروژهتان به شدن پایین میآید و زبانی هم که با آن برنامهنویسی میکنید به همان مقدار به شما واکنش نشان خواهد داد ( هر کُنشی واکنشی دارد...!? ) کاهش سرعت اجرا، زیادنویسی، اگه برای سایر توسعهدهندههای دیگر باشد، به احتمال زیاد طرف پروژهی شما نمیآیند! به عنوان مثال، تعریف متغییر بدون آرایه؛ let number_one : Int8 = 1 let number_two : Int8 = 2 let number_three : Int8 = 3 let number_four : Int8 = 4 let number_five : Int8 = 5 let number_six : Int8 = 6 let number_seven : Int8 = 7 let number_eight : Int8 = 8 let number_nine : Int8 = 9 let number_ten : Int8 = 10 خودتان باشید، حاضرید به این شکل پروژهای را به این شکل پیش ببرید؟! حالا فکر کنید ۱۰۰۰ دادهی مختلف بخواهید تعریف کنید! تعجب میکنید، اینطور نیست؟! اما خوشبختانه همیشه راه نجات هست... آن هم استفاده از آرایهها است! آرایهها به شما کمک میکنند تا دادههای زیادی که مورد نیاز پروژهی شما باشد، تعریف و استفاده کنید. نحوهی تعریف به سه روش میتوانید آرایههای خودتان را تعریف کنید؛ استفاده از نوع و سازنده ( Construct ) استفاده از کلاس Array، نوع متغییر و سازنده تعریف آرایه بدون هیچ واسطهای! نکته آرایههای سوئیفت از موقعیت ( Index ) صفر ( ۰ ) شروع خواهند شد. در ادامه متوجه این موضوع خواهید شد، اما همیشه این را به خاطر داشته باشید که اولین عضو در یک آرایه در موقعیت صفرم آن آرایه قرار میگیرد و به همین ترتیب، موقعیت اول، حاکی از مقدار دوم، موقعیت دوم، مقدار سوم و الی آخر... پس این مورد را در پروژههایتان حواستان باشد! چرا که با یک اشتباه، ساعتها زمان و انرژی خود را تَلف میکنید تا یک اشتباه کوچک را پیدا و رفع کنید. اولین مورد که در لیست بالا گفته شده، به این صورت است که شما یک متغییر تعریف میکنید ( از کلمات کلیدی var و یا let میتوانید استفاده کنید) و بعد یک نام شفاف و دلخواه خواهید نوشت و در نهایت از نوع و سازنده به این شکل استفاده میکنید؛ var first_array = [Int]() print(first_array) // Output is empty or [] در روش دوم میتوانید از کلاس Array استفاده کنید! به این شکل که مشاهده میکنید؛ var first_array = Array<Int>() print(first_array) // Output is empty or [] و در نهایت میتوانیم بدون هیچ واسطهای ( بدون استفاده روش اول و دوم )، آرایهمان را تعریف کنیم؛ var first_array = [1,2,3,4,5,6,7,8,9,10] print(first_array) // Output is [1,2,3,4,5,6,7,8,9,10] به نظر میآید که این برای شما راحتتر و قابلدرکتر باشد تا موارد قبل، اینطور نیست؟ اما خُب، آنها را هم برای دوستانی که عاشق پیچدگی هستن نوشتیم! شما میتوانید از هر روشی که مدنظرتان بود استفاده کنید. نوع دادهای هم که مشخص میکنید، بستگی به پروژهی شما دارد؛ var first_array = ["www.iostream.ir","www.fanoox.ir","www.ModernCpp.ir"] print(first_array) // Output is empty or ["www.iostream.ir", "www.fanoox.ir", "www.ModernCpp.ir"] همینطور شما میتوانید از مقادیری پیشفرض برای آرایههایتان ستفاده کنید! به عنوان مثال شما در همان موقعی که تعریف آرایهی خودتان را انجام میدهید، میخواهید تا ۱۰ خانه از آرایهتان دادههای تکراری داشته باشد. اینکار را میتوانید با استفاده از سازنده ( Construct ) انجام بدهید؛ var first_array = [Int](repeating: 20, count: 10) print(first_array) // Output is [20,20,20,20,20,20,20,20,20,20] در کد بالا گفته شدهکه عدد ۲۰ را ( repeating: 20 ) به تعداد ۱۰ بار ( count: 10 ) در آرایهی first_array قرار گیرد. خروجی را همانطور که مشاهده میکنید، مقدار ۲۰ به تعداد ۱۰ بار در first_array تکرار شده. ترکیب دو آرایه با هم برای اینکار فقط کافی است با استفاده از آپِریتر +، یک آرایهی جدید بدست بیاوریم؛ var first_array = [1,2,3,4,5] var two_array = [6,7,8,9,10] var result_array = first_array + two_array print(first_array) // Output is [1,2,3,4,5,6,7,8,9,10] دسترسی به کُل یا یک از دادههای آرایه برای اینکه بتوانید به کل آرایه دسترسی داشته باشید و آن رو نمایش بدهید، میتوانید به این صورت عمل کنید؛ var first_array = [1,2,3,4,5] print(first_array) // Ouput is [1,2,3,4,5] البته میتوانید در مواقعی که نیاز به آرایه کامل دارید استفاده کنید! به عنوان مثال پارامتر توابع و ... برای اینکه بتوانید به یک دادهی خاص که موردنظر شما است، دسترسی داشته باشید؛ باید از موقعیت ( Index ) آرایه استفاده کنید؛ var website_name = ["www.iostream.ir","www.fanoox.com","www.ModernCpp"] var langauge_name = ["C++","C","Swift"] print(website_name[0]) // Output is www.iostream.ir print(langauge_name[2]) // Ouput is Swift در قطعه کد بالا، ابتدا باید نام آرایه بیاورید و بعد از آن با استفاده از دو براکت ( [] ) و قرار دادن شماره موقعیت، به مقدار آن دسترسی داشته باشید. همانطور هم که مشاهده میکنید، گفتیم که آرایهها از موقعیت صفرم شروع میشوند که در بالا با آوردن website_name و سپس شماره موقعیت ( Index Number ) به اولین عضو آن یعنی www.iostream.ir دسترسی پیدا کرده و آن را نمایش میدهیم. اگر از ۲ برای آرایه استفاده کنید، به شما خروجی Swift را خواهد داد! چرا که عضو دوم آرایهی langauge_name مقدار Swift است. اضافه کردن داده به آرایه اگه بخواهیم یک عضو ( مقدار جدید ) به آرایه اضافه کنیم، از متُد append که مربوط به کلاس آرایهها است، استفاده میکنیم. در جلسههای بعد با کلاسها، و متدها آشنا خواهید شد. به این مثال توجه کنید؛ var first_array = [1,2,3,4,5] // Before print("Before \(first_array)") // Ouput is [1,2,3,4,5] first_array.append(6) // After print("After \(first_array)") // Output is [1,2,3,4,5,6] با استفاده از موقعیت ( Index ) میتوانیم یک مقدار را به یک موقعیت یا همان خانهای از آرایه که مشخص کردیم، اضافه کنیم؛ var first_array = [1,2,3,4,5] first_array[0] = [10] print(first_array) // Output is [10,2,3,4,5] یا میتوانیم از آپِریتر ترکیبی =+ استفاده کنیم برای اضافه کردن گروهی از دادهها؛ var first_array = [1,2,3,4,5] // Before print(first_array) // Ouput is [1,2,3,4,5] first_array += [6,7,8,9,10] // After print(first_array) // Output is [1,2,3,4,5,6,7,8,9,10] با استفاده از متد insert میتوانید یک عضو جدید را به موقعیتی ( Index ) که مدنظرتان است، اضافه کنید! به عنوان مثال در آرایهی زیر، میخواهید که عدد ۳، در خانه یا موقعیت آخر قرار بگیرد؛ var first_array = [1,2,3,4,5] // Before print("Before \(first_array)") // Ouput is [1,2,3,4,5] first_array.insert(6, at: 4) // After print("After \(first_array)") // Output is [1,2,3,4,5,6] این متد دو پارامتر دریافت میکند؛ یکی برای عضو جدید و یکی دیگر برای موقعیتی که میخواهید عضو جدید قرار بگیرد که همانطور که مشاهده میکنید، مقدار ۶ در موقعیت آخر قرار گرفته است که مقدار ۵ را دارد. حذف یک عضو برای حذف یک مقدار از آرایه، از متدهای remove و removeLast استفاده میکنیم. اولین متد؛ یک موقعیت مشخص برای حذف عضو میخواهد، در حالی که متد دوم؛ آخرین عضو را حذف میکند؛ var first_array = [1,2,3,4,5] // Before remove print("Before \(first_array)") // Ouput is [1,2,3,4,5] first_array.remove(at: 0) // After remove print("After \(first_array)") // Output is [2,3,4,5] // Using removeLast first_array.removeLast() print(first_array) // Output is [2,3,4] با استفاده از at: 0 در متد remove مشخص کردیم که میخواهیم عضو اول را حذف کنیم که در خروجی هم میتوانید ببینید و در متد removeLast آخرین عضو آرایه ( در این مثال 5 ) رو حذف کردیم. و در نهایت شما میتوانید در یک رِنج ( بازه ) مشخص؛ که تعیین میکنید، عضو اضافه کنید! چیزی شبیه به حلقهی for! این مثال را ببینید؛ var first_array = [1,2,3,4,5] first_array[0...4] = [6,7,8,9,10] print("Before \(first_array)") // Ouput is [6,7,8,9,10] گردش در آرایه گردش یعنی اینکه بتوانیم بین اعضای یک آرایه که یکی یکی آنها را انتخاب میکنیم، کارهایی را که مدنظرمان است را انجام دهیم! که با استفاده از یک حلقهی for میتوانیم در عضوهای آن این کار را انجام دهیم. به این مثال توجه کنید؛ var first_array = [1,2,3,4,5] for item in first_array { print("Item : \(item)") } /* Item : 1 Item : 2 Item : 3 Item : 4 Item : 5 */ اگه بخواهیم که هم موقعیت ( Index ) و هم مقدار آرایه رو داشته باشیم؛ از متد enumerated استفاده میکنیم که به ما یک تاپِل ( Tuple ) خواهد داد ( در جلسات بعد بعدا مفصلا دربارهی تاپل صحبت خواهیم کرد) و در حلقه استفاده میکنیم؛ var first_array = [1,2,3,4,5] for (index,item) in first_array.enumerated() { print("Index of : \(index) and Item : \(item)") } /* Index of : 0 and Item : 1 Index of : 1 and Item : 2 Index of : 2 and Item : 3 Index of : 3 and Item : 4 Index of : 4 and Item : 5 */ Count و isEmpty ( دو ویژگی از کلاس آرایه ) شاید بخواهید بدانید تعداد عضوهای یک آرایه به چه تعدا هستند؟ این مورد به خصوص در حلقهها و یا موقعیتهای دیگر بسیار موثر خواهد بود! برای اینکار از ویژگی ( Property ) به نام count استفاده میکنیم که فقط خواندنی ( read-only ) است و هیچ مقداری رو نمیتوانید به آن ضافه کنید! ( درمورد ویژگیها مفصلا در جلسات بعد توضیح خواهیم داد ) و فقط میتوانید از مقدار آن که تعداد اعضای آرایه است، استفاده کنید؛ var first_array = [1,2,3,4,5] print(first_array.count) // Output is 5 اگه هم میخواهید خالی بودن یا نبودن یک آرایه را بررسی کنید؛ متد isEmpty این امکان را در اختیار شما قرار داده است؛ var first_array = [1,2,3,4,5] if first_array.isEmpty { print("Empty") } else { print("Not Empty") } // Not Empty امیدواریم که این جلسه مورد رضایت شما عزیزان باشد.
-
عالی بود آقا کامبیز، ممنون از شما ?
-
آموزش زبان برنامهنویسی سوئیفت - جلسه پنجم مواردی که در این جلسه یاد خواهید گرفت: متغییر آپشِنال (Optionals Variable ) ، رشتهها و کارکترها (String & Character ) متغییرهای آپشِنال ( Optionals Variable ) چیستند؟ این نوع متغییرها، برای مدیریت دادهی شما استفاده میشوند! همانطور که از نام آنها هم مشخص است، به معنی اختیاری! یعنی یا یک مقدار وجود دارد یا ندارد! در سوئیفت، شما باید بعد از تعریف یک متغییر مقدار آن را هم تعیین کنید و نمیتوانید آن را بدون مقدار به حال خود رها کنید! به عنوان مثال کُد زیر را ببینید: var website_name print(website_name) // Error compiler در صورتی که این کد را اجرا کنید، با خطای کامپایلر مواجه میشوید. دلیلش هم آن است که در این زبان، باید مقدار هر متغییر را باید بلافاصله بعد از تعریف آن بدهید و حالت پیشفرض نخواهیم داشت ( در برخی از زبانها حالت پیشفرضی برای متغییرها در نظر گرفته میشود مانند ++C ) این موضوع با نوع هم بخواهید تعریف کنید باز هم به خطای کامپایلر خواهید خورد: var website_name : String print(website_name) // Error compiler اما اگر به آن مقدار خالی ( "" => دابل کوتیشن ) بدهید، خروجی را برای شما نمایش خواهد داد، اما فقط خالی!: var website_name : String = "" print(website_name) // Print empty این برای همهی نوعهای دادهی دیگر هم صدق میکند. اما هر دفعه در کدهای خودتان برای بررسی کردن آنها باید شرط بگذارید ( if,else,ifelse و .. ) که ببینید کداممتغییر مقدار دارد یا ندارد. از این گذشته، با اینکار کدهای تمیزی هم نخواهید داشت. پس اینجا باید از آپشنالها استفاده کنیم. به این قطعه کد دقت کنید: var website_name : String? // website_name is automatically set to nil if name == nil{ print("website_name has nil value") } در مثال بالا، شما تعریف متغییر آپشنال ( Optional ) را میبینید که با علامت سوال ( ? ) همراه است. ابتدا شما باید، کلمهی کلیدی var را همراه با یک اسم، بیاورید و بعد با استفاده از دو نقطه ( : ) که کالُن در برنامهنویسی خوانده میشود استفاده کنید. و درنهایت به همراه نوع داده و علامت سوال را در جهت انگلیسی ( ? ) قرار میدهید. متغییر شما در حال حاضر مقدار nil را دارد که به صورت اُتوماتیک، به متغییر شما داده شده است که خود شما هم میتوانید این مقدار را برای تمای متغییرهای آپشنال خودتان قرار دهید. nil به معنای هیچ یا هیچچیز است. یعنی الان هیچ دادهای ندارید. حالا شما میتوانید هر زمانی که خواستید، به متغییر خود مقدار بدهید. نکته متغییر آپشنال شما به اصطلاح ( Wrapper ) به معنی بستهبندی، روپوش شده است! یعنی اینکه دادههای متغییر شما بستهبندی شده و در هنگامی که نیاز به اطلاعات آن داشتید باید با استفاده از علامت تعجب ( ! ) آن را ( Unwrapper ) کنید و یا از حالت بستهبندی شده خارج و اطلاعات خودتان را دریافت کنید! به عبارتی دیگر، اطلاعاتی که شما در متغییر خودتان ذخیره کردید در حالت آپشنال، بین دو پرانتز قرار گرفتند و به همین خاطر به آن میگویند Wrapper یا محافظت شده است!. به این مثال دقت کنید: var website_name : String? = "www.iostream.ir" if name == nil{ print("website_name has nil value") } else{ print(website_name!) // Print www.iostream.ir } همانطور که در مثال بالا مشاهده میکنید، اگه متغییر ما مقداری نداشت ( nil )، شرط اول اجرا خواهد شد و در غیر اینصورت، مقدار www.iostream.ir نمایش داده میشود. شما میتوانید در هر زمانی که نیاز داشتید، متغییر خودتان را برابر با nil کنید: var website_name : String? = "www.iostream.ir" website_name = nil if name == nil{ print("website_name has nil value") } else{ print(website_name!) // Print www.iostream.ir } خروجی برابر است با؛ website_name has nil value. به خاطر داشته باشید که به هیج وجه نمیتوانید به متغییرهای عادی کلمهی کلیدی nil رو بدهید! این فقط برای متغییرهای آپشنال است. رِشتهها و کارِکترِها (String & Character ) رشتهها مجموعهای از کارکترها هستند که یک حرف یا یک متن کامل را درون خودشان ذخیره میکنند ( همان متن یا نوشته ). مانند "www.iostream.ir" و یا "Apple". و کارکترهایی که در نهایت میتوانند تا دو حرف را در خودشان ذخیره کنند، مثل؛ "AP" و یا "IO". بگذارید چند نمونه بیاوریم تا بهتر و شفافتر متوجه بشوید: let website_name : String = "www.iostream.ir" print(website_name) و یا اینکه یک کارکتر داشته باشیم؛ let company_name : Character = "A" print(company_name) دقت داشته باشید که در حال حاضر که این زبان در این نسخهی یعنی ( 5.1 ) به سر میبرد، تنها از یک کارکتر پشتیبانی میکند اما در مورد کارکترهای یونیکُد ( Unicode ) اینگونه رفتار نمیکند و هیچ اخطاری از سمت کامپایلر، داده نمیشود. به این مثال دقت کنید؛ let unicode_character : Character = "\u{1F1EE}\u{1F1F7}" print(unicode_character) // Ouput iran flag در خروجی میتوانید مشاهده کنید که پرچم کشورمان نمایش داده میشود و آن هم به دلیل استفاده از کارکترهای یونیکد است. بنابراین، در این مورد بدون اینکه نوع دادهی کارکتر ( Character ) به کارکترهای یونیکد، ایرادی بگیرد، معادل آن را که حاوی یک کارکتر است ( در این مثال پرچم ایران که خود یک کارکتر است ) ذخیره میکند. اما درمواردی دیگر به علت اینکه که کارکتر یونیکدی نخواهیم داشت، بیشتر از یک کارکتر بخواهیم ذخیره کنیم باید از نوع دادهی رشته ( String ) استفاده کنیم نه Character. تعریف رشته شما با تعریف یک متغییر یا ثابت، نام آن و در نهایت نوع و مقدار آن، میتوانید یک رشته یا همان دنبالهای از کارکترها داشته باشید. و یا از سازنده (در محبث کلاسها کامل دربارهی آن توضیح خواهیم داد) خود نوع String استفاده کنید؛ let website_name : String = String("www.iostream.ir") print(website_name) یا اینکه به صورت کوتاه شده، بدون تعریف صَریح نوع، آن را به این شکل بنویسید: let website_name = "www.iostream.ir" let platform_name = String("www.fanoox.com") print("Website name : \(website_name) and Platfrom name : \(platform_name)") خالی قرار دادن رشته ما میتوانیم به دو صورت به متغییرها رشتهای خود مقدار خالی بدهیم! یا با استفاده از دو دابِل کُوتِیشِن ( "" ) یا با استفاده از یک نمونه از نوع رشته ( ()String ). به مثالهای زیر دقت کنید: let website_name = "" let platform_name = String() print(website_name,platform_name) // Empty بررسی خالی بودن یا نبون رشته شما میتوانید با استفاده از ویژگی isEmpty از کلاس String، بررسی کنید که آیا متغییر شما خالی است یا نه؟ به مثال زیر دقت کنید: let website_name = "" if website_name.isEmpty { // True print("website_name is empty!") } متصل کردن دو رشته با استفاده از آپِریِتر + شما میتوانید دو یا چند رشته را به هم متصل کنید؛ let website_name : String = "www.iostream.ir" let platform_name : String = "www.fanoox.com" let addition : String = website_name + " and " + platform_name print(addition) // www.iostream.ir and www.fanoox.com یا اینکه از حالت کوتاه شدهی آن استفاده کنید؛ let website_name : String = "www.iostream.ir" let platform_name : String = "www.fanoox.com" website_name += " and " + platform_name print(addition) // www.iostream.ir and www.fanoox.com ترکیب اطلاعات با یک رشته همچنین شما میتوانید یک رشتهی حاوی اطلاعات داشته باشید و در عین حال آنها در خروجی برای ذخیره در متغییرهای دیگر استفاده کنید! چگونه؟ به این صورت؛ let website_name : String = "www.iostream.ir" let platform_name : String = "www.fanoox.com" let addition = "Website name : \(website_name) and Platfrom name \(platform_name)" print(addition) // Website name www.iostream.ir and Platform name www.fanoox.com با استفاده از این الگو ()\ شما میتوانید تا بینهایت اطلاعات در داخل یک رشته قرار بدهید! فقط کافی است متغییرها، ویژگیهای یک کلاس، توابعی که مقدار برگشتی دارند ( درمورد توابع در جلسات بعد کاملا صحبت خواهیم کرد ) و هر چیزی که حاوی داده یا همان اطلاعات باشد قرار بدهید. اول یک اِسلش رو به عقب ( Backward Slash ) و بعد از آن هر اطلاعاتی که میخواهید داخل رشته باشند را داخل دو پرانتز () قرار میدهید. بدست آوردن طول یک رشته برای به دست آوردن طول یک رشته از ویژگی count از کلاس String استفاده میکنیم؛ let website_name : Stirng = "www.iostream.ir" print(website_naem.count) // website_name length is 15 اگر تکتک کارکترهای www.iostream.ir را بشمارید، میبینید که مقدار 15 به دست میآید. پس در خروجی هم عدد 15 را خواهیم داشت. مقایسه دو رشته اگه بخواهید یک رشته را با یک رشتهی دیگه مقایسه کنید، میتوانیم بطور مستقیم یا با استفاده از شرطها این کار را انجام دهیم؛ let website_name : String = "www.iostream.ir" let platform_name : String = "www.fanoox.com" print(website_name == platform_name) // False if website_name == platfrom_name { // False print("Equal") } else { print("Not Equal") // Not Equal } با آپِریِتر == در شرط if بررسی میکنیم که آیا website_name و platform_name با هم مساوی هستند یا نه، که Not Equal یعنی برابر نیستند را در خروجی خواهیم داشت. بررسی شروع یا پایان یک رشته با دو متد ( در جلسات آینده با متدها کاملا آشنا خواهید شد ) hasPrefix و hasSuffix میتوانیم بررسی کنیم که آیا رشتهی ما با ورودی که میدهیم، مطابقت دارد یا نه. به عنوان مثال رشتهی www.iostrea.ir رو میخواهیم بررسی کنیم که با www شروع میشود یا نه. برای این کار از متد hasSuffix استفاده میکنیم: let website_name : String = "www.iostream.ir" print(website_name.hasSuffix("wwww")) // False // Or if website_name.hasSuffix("www") { // True print(website_name) // www.iostream.ir } خروجی اول False است! چرا که ورودی ما ( wwww ) است و با اول رشتهی www.iostream.ir مطابقت ندارد ولی در دستور شرطی ( if ) که گذاشتیم، مقدار True است. چرا که ورودی ما ( www ) با اول www.iostream.ir مطابقت دارد. حالا اَگه بخواهیم که آخر رشتهی خود را بررسی کنیم که آیا آن چیزی که میخواهیم، با آخر رشته تمام میشود یا نه، از متد hasPrefix استفاده میکنیم: let website_name : String = "www.iostream.ir" print(website_name.hasPrefix(".com")) // False // Or if website_name.hasPrefix(".ir") { // True print(website_name) // www.iostream.ir } خروجی False و www.iostream.ir است. آخر دامنه وبسایت www.iostream.ir با ( ir. ) تمام میشود اما ما دامنهی com. را قرار دادیم که در نتیجه False خواهد شد. ولی در دستور شرطی یعنی if این موضوع درست است! چرا که دامنهی وبسایت با ir. تمام خواهد شد و این متد هم همین را میخواهد! پس در نتیجه True و مقدار متغییر website_name نمایش داده میشود. امیدواریم که این جلسه مورد رضایت شما عزیزان قرار گرفته باشد.
-
ممنونیم، مهندسجان.
-
آموزش زبان برنامهنویسی سوئیفت - جلسه چهارم مواردی که در این جلسه یاد خواهید گرفت: کامنتها، دو ویژگی نوعهای داده Int، آپِریِترها ( Operators )، کلمات کلیدی break,continue,fallthrough کامنتها در زبان برنامهنویسی سوئیفت مثل اکثر زبانهای برنامهنویسی دیگر، از کامنتها استفادهای زیادی میشود و معمولا برای اهدافی کامنتها استفاده میشوند و میتوانند شامل موارد زیر باشند: برای غیرفعال کردن موقتی یک قسمت یا بخشی از کُد برای توضیح دادن کدها برای دیگر برنامهنویسان یا توسعهدهندگان یا توضیح کد برای اینکه در مراجعات بعدی به پروژه کارکرد همان قسمتی که کامنت کردید را متوجه شوید انواع کامنتها در زبان برنامهنویسی سوئیفت؛ تَک خطی ( single-line ) چند خطی ( multi-line ) در کامنت تک خطی، با گذاشتن دو علامت // میتوانید توضیحات خود را فقط در همان خط درمورد کُد مورد نظر بنویسید و بعد از آن کامنت شما در واقع در حال تعریف دستور جدید هستید! این کامنت، به این صورت استفاده میشود؛ let _web_site_name : String = "www.iostream.ir" print(_web_site_name) // Ouput the string of www.iostream.ir در مثال بالا همانطور که مشاهده میکنید از کامنت تک خطی استفاده کردیم، و بعد از این کامنت شما نمیتوانید انتظار داشته باشید که در خط جدید دوباره حالت کامنتگذاری برای شما همچنان فعال باشد! چرا که در خط بعدی دستوری جدید داریم نه کامنتی ادامهی کامنت قبل!. و اما کامنت چند خطی که میتوانید در تعداد خطهای بیشتر، توضیحات خود را بنویسید؛ let _web_site_name : String = "www.iostream.ir" /* We can also use from of print("String.. and \(_web_site_name)") */ print(_web_site_name) در مثال بالا که مشاهده میکنید، شما هیچ محدودیتی برای اضافه کردن توضیحات بیشتر برای خود کدهای خود ندارید و تا هر چند خط توضیحات که مدنظرتان بود، میتوانید استفاده کنید. دو ویژگی نوع دادهی Int اگر بخواهیم کوچکترین و بزرگترین عدد موجود از نوع دادهی Int را بدست آوریم، از دو ویژگی max,min استفاده میکنیم. هر دو ویژگی به همراه مثال در زیر آورده شدهاند؛ print("Max => \(Int.max)") print("Min => \(Int.min)") با اجرای کدهای بالا، بزرگترین مقدار موجود نوع دادهی Int و همچنین کوچکترین آن به شما نمایش داده خواهد شد. آپِریِترها ( Operators ) آپریترها در هر زبان برنامهنویسی به عنوان پایه و اساس محاسبات و در بعضی موارد برای کارهای دیگر استفاده میشوند. محاسباتی مانند، جمع، تفریق،تقسیم،ضرب و باقی مانده و ... در سوئیفت این 8 دسته آپریتر وجود دارد: اِنتسابی ( Assigment Operator ) محاسباتی ( Arithmetic Oprerator ) باقیمانده ( Remainder Operator ) مُرکب ( Compound Assigment Operator ) مقایسهای ( Comparison Operators ) ترِنِری ( Ternary Conditonal Operators ) دامِنه ( Range Operator ) منطقی ( Logical Operators ) اینها، کل آپریترها در سوئیفت هستند که هر کدام عمل مخصوص به خود را انجام میدهند. در مثالهای زیر هر کدام از اینها را به همراه مثال برای شما آوردهایم. آپریتر اِنتسابی ( Assigment Operator ) اگر ما یک مقداری را به متغییری انتساب میدهیم، عملا داریم از آپِریِتر انتساب ( = ) استفاده میکنیم. چرا که کدنویسی از سمت چپ شروع میشود و این هم کاملا منطقی هم است که مقدار دهی به یک متغییر از سمت چپ صورت میگیرد و مقدار سمت راست را درون خود ذخیره میکند. به این مثال دقت کنید؛ let _web_site_name : String = "www.iostream.ir" // Assigment Operator ( = ) print("Type of \(type(of : _web_site_name ) and the website of name \(_web_site_name)") در مثال بالا مشاهده میکنید که مقدار www.iostream.ir که یک مقدار رشتهای/متنی است را در متغیر web_site_name ذخیره میکنیم. این کار با استفاده از این علامت ( = ) انجام شده است. در خط بعد هم نوع متغییر و مقدار موجود در متغییر web_site_name که ذخیره شده است را نمایش میدهیم. آپریترهای محاسباتی ( Arithmetic Oprerator ) در قسمتهایی از پروژه پیش آمده که ما باید محاسباتی را انجام بدهیم. این کار با استفاده از این آپریترها انجام میشود. که شامل: +،-،/،* و ٪ هستند. برای هر کدام از اینها، مثالهایی در زیر آورده شده است؛ جمع ( + ) var number_one, number_two : Int8 number_one = 50 number_two = 50 print("Result = > ", number_one + number_two) // Output the number 100 در مثال بالا همان طور که مشاهده میکنید، ابتدا دوم متغییر با نوع Int8 تعریف کردهایم و سپس در خطوط بعد به آنها مقادیر ۵۰ را دادهایم. در نهایت عمل جمع ( + ) را روی آنها به صورت مستقیم انجام داده و نمایش میدهیم. یا اگر سادهتر بخواهیم تعریف کنیم، آپریتر ( + ) عمل جمع کردن اعداد و یا متصل کردن دو رشته را بر عهده دارند؛ var web_site_name, platform_name : String web_site_name = " www.iostream.ir :)" platform_name = " www.fanoox.com ;)" print("Binding two string => ", web_site_name + platform_name) // Ouput the website name and platform name => www.iostream.ir :) www.fanoox.com ;) و به همین راحتی میتوانید تا بینهایت عمل جمع و متصل کردن رشتهها را انجام دهید. تنها نکتهای که باید توجه داشته باشید این است که سوئیفت در برخورد با اعداد و این آپریتر، آن عبارت را محاسباتی در نظر میگیرد و در برخورد دو یا چند رشته، آن عبارت را عمل متصل کردن و الحالق ( Concatentation ) در نظر میگیرد. تفریق ( - ) برای کم کردن دو مقدار عددی از هم استفاده میشود؛ var number_one, number_two : Int8 number_one = 80 number_two = 30 print("Result => ", number_one - number_two) // Output the number 50 مثال بالا به خوبی نشان میدهد که دو مقدار ۸۰ و ۳۰ از هم کم شده و در نتیجه، خروجی برابر ۵۰ خواهد بود. ضرب ( * ) عمل ضرب کردن دو عدد را انجام میدهد؛ var number_one, number_two : Int8 number_one = 50 number_two = 20 print("Result => ", number_one * number_two) // Output the number 1000 دقت کنید که نباید به حرف ( x ) که شبیه به ضرب در ریاضیات است اشتباه گرفته شود. تقسیم ( / ) عمل تقسیم کردن دو عدد را انجام میدهد؛ var number_one, number_two : Double number_one = 50.0 number_two = 20.0 print("Result => ", number_one / number_two) // Output the number 2.5 در محاسباتی که عمل تقسیم را انجام میدهیم باید به این نکته دقت کنیم که اگر پروژهی ما عملا برای محاسبات کار خاصی است باید از نوع دادهی Double یا Float استفاده کنیم که البته در محاسبات معمولی، نوع دادهی Float جوابگوی نیاز ما هم هست، اما در محاسباتی که نیاز به دقت بالایی دارند باید از نوع دادهی Double استفاده کنیم. باقیمانده ( ٪ ) توجه داشته باشید که این علامت را با درصد که شبیه همین است اشتباه نگیرید! چرا که در دنیای واقعی ما، علامت درصد برای نشان دادن مقداری از چیزی در یک محصول یا خدمات است ولی در دنیای کامپیوتر و برنامهنویسی این علامت، به معنای باقی ماندهی بین دو عدد است که بعد از تقسیمهای پیدرپی که صورت میگیرد، بدست میآید. این باقی مانده یا ۰ است یا ۱ ( حتما شما هم عاشق صفر و یکی هستید که اساس کار کامپیوتر و سیستم شما را تشکیل میدهد! ). این مثال را ببینید تا بهتر متوجه این موضوع شوید؛ var number_one, number_two : Int8 number_one = 10 number_two = 2 print("Result => ", number_one % number_two) // Output the number 0 اگر جزئیتر بخواهیم وارد شویم به این صورت است که ابتدا عدد ۱۰ بر ۲ تقسیم ( / ) شده و سپس حاصلی که بدست میآید ۵ است و سپس دوباره ۵ تقسیم بر ۲ شده و ۲ بدست میآید و در اینجا باقیمانده ۲ ٪ ۲ میشود ۰. آپِریِترهای مُرکب ( Compound Assigment Operator ) که شامل عبارتهای کوتاهشده یا به اصطلاح میانبری برای عمل انتساب و محاسبه را فراهم میکند که شامل: =+،=-،=*،=/،=٪ است. در زیر توضیح مختصر به همراه یک مثال آورده شده است. انتساب و جمع ( =+ ) در این حالت ما هم عمل انتساب را داریم و هم عمل جمع، با یک تیر دو نشان بزنید! به مثال زیر دقت کنید. var number_one : Int8 = 50 number_one += 50 print("Result =>", number_one) // Output the number 100 در خط دوم که ما با آن کار داریم، متغییر number_one مقدار ۵۰ را هم به آن اضافه به خودش اضافه کرده و در نهایت در خود متغییر number_one ذخیره و نتیجه ۱۰۰ نمایش داده میشود. که بدون استفاده از میانبر، به این شکل بود؛ var number_one : Int8 = 50 number_one = number_one + 50 print("Result =>", number_one) // Output the number 100 حتی میتوانیم برای اتصال یک رشته به رشتهی دیگر استفاده کنیم؛ var web_site_name : String = "www.iostream.ir :) " web_site_name += " www.fanoox.com ;) " print("Result =>" web_site_name) // Ouput the web site of name => www.iostream.ir :) www.fanoox.com ;) که در شکل ساده به این شکل نوشته میشد؛ var _web_site_name_and_platform_name : String = "www.iostream.ir :) " + " www.fanoox.com ;) " print("Result => ", _web_site_name_and_platform_name) // Ouput the web site of name and platform name => www.iostream.ir :) www.fanoox.com ;) انتساب و تفریق ( - ) مقدار سمت راست را از مقدار سمت چپ کم میکند و نتیجه در همان متغییر ذخیره خواهد شد؛ var number : Int8 = 80 number -= 30 print("Result =>", number) // Ouput the number 50 مقدار ۸۰ که مقدار فعلی متغییر number است، از مقدار ۳۰ که در سمت راست متغییر قرار دارد، کم میشود و در نهایت مقدار ۵۰ در همان متغییر یعنی number ذخیره خواهد شد. انتساب و ضرب ( =* ) ضرب مقدار سمت راست در مقدار فعلی متغییر سمت چپ را انجام میدهد؛ var number : Int8 = 80 number *= 30 print("Result =>", number) // Ouput the number 2400 انتساب و تقسیم ( / ) مشابه آپِریِتر تقسیم ( / )، تقسیم مقدار سمت راست را به متغییر سمت چپ انجام میدهد؛ var number : Int8 = 10 number /= 2 print("Result =>", number) // Ouput the number 5 انتساب و باقیمانده ( ٪ ) عمل باقیماندهی دو عدد که شامل مقدار فعلی متغییر سمت چپ و مقدار سمت را است را محاسبه کرده و در متغییر سمت چپ ذخیره میکند؛ var number : Int8 = 10 number ٪= 5 print("Result =>", number) // Ouput the number 0 آپِریِترهای مقایسهای ( Comparison Operators ) برای مقایسهی بین دو مقدار و در نتیجه به دست آوردن مقدار True یا False مورد استفاده قرار میگیرند. بیشترین استفادهی آنها در شرطها است، اما میتوان به صورت مستقیم هم از آنها هم استفاده کرد. این آپِریِترها شامل ==،=!،>،<،=<،=>،==!،=== هستند. برای هر کدام مثالی در زیر آورده شده است. مساوی ( == ) برای مقایسه دو مقدار استفاده میکنیم که در صورتی که مقادیر دو طرف مساوی باشند، مقدار True و در غیر اینصورت مقدار False برگشت داده خواهد شد؛ print("True and False => ", 2 == 2) // Output the true print("True and False => ", 2 == 3) // Output the false در مثال بالا به دلیل اینکه ۲ با ۲ برابر است، مقدار نمایش داده شده، true است. و در خط بعدی به این دلیل که مقدار ۲ برابر با ۳ نیست، مقدار false نمایش داده میشود.همچنین میتوانید در شرطها و حلقهها هم استفاده کنید: if 2 == 2 { print("Ok!") }else { print("NO!") } // Ouput the string Ok! نامساوی ( =! ) اگر مقدار برابر با مقدار مقابل خودش نباشد، نتیجه true و در غیر اینصورت نتیجه false خواهد بود. علامت ! ( نَقیض ) دقیقا معنا و مفهوم ( == ) را عوض میکند ( یعنی اگر مقداری true باشد، برعکس شده ( false ) و اگر false باشد ( true ) میشود. print("True and False => ", 2 != 3) // Output the true print("True and False => ", 2 != 2) // Output the false در مثال بالا، ۲ مساوی ۳ نیست و این درست است!. در خط بعدی ۲ برابر با ۲ است و این درست است! که در نتیجه، برعکس آن یعنی false نمایش داده میشود. کوچکتر ( > ) اگر مقدار سمت چپ کوچکتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false است؛ print("The operator ( < ) => ", 1 < 2) // Output the boolean true print("The operator ( < ) => ", 2 < 1) // Output the boolean false بزرگتر ( < ) اگر مقدار سمت چپ بزرگتر از مقدار سمت راست بود، نتیجه true و در غیر اینصورت نتیجه false خواهد بود؛ print("The operator ( > ) => ", 1 > 2) // Output the boolean false print("The operator ( > ) => ", 2 > 1) // Output the boolean true بزرگتر یا مساوی ( =< ) اگر مقدار سمت چپ، بزرگتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false خواهد بود؛ print("The operator ( >= ) => ", 1 >= 1) // Output the boolean true print("The operator ( >= ) => ", 1 >= 2) // Output the boolean false کوچکتر یا مساوی ( => ) اگر مقدار سمت چپ، کوچکتر یا مساوی مقدار سمت راست بود، نتیجه true است، در غیر اینصورت، نتیجه false است؛ print("The operator ( <= ) => ", 1 <= 2) // Output the boolean false print("The operator ( <= ) => ", 1 <= 1) // Output the boolean true نکته: اولویت مساوی ( = ) در این مورد بالاتر از بزرگتر < یا کوچکتر > است و بنابراین در حلقهها اگر این آپِریِتر باشد، اولویت با آن است. مقایسهی دو شئ ( === ) برای مقایسهی دو شئ ( object ) استفاده میشود. اگر هر دو شئ از یک مرجع ( refrence ) باشند یا به عبارت دیگر شئهای ساخته شده در حافظهی به نام Heap با تمام ویژگیها و متغییرها نگهداری شوند و اگر شئ دیگر از همان حافظهای که یک شئ دیگر استفاده میکند وجود داشته باشد، این آپِریِتر درمورد آن دو شئ نتیجهی true و در غیر اینصورت نتیجهی false را نمایش میدهد. در مبحث شئگرایی بیشتر در این مورد صحبت خواهیم کرد، در حال حاضر فقط همین را که بدانید، کافیست. به مثال زیر دقت کنید: class WebsitePlatform { var website_name, platform_name : String init(web_name : String, platform : String) { self.website_name = web_name self.platform_name = platform } } let _web_site_and_platform_one = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _web_site_and_platform_two = WebSitePlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _website_and_platform_one === _website_and_platform_two { print("This is refrence!") }else { print("No,this is not refrence!") } اگر این قطعه کد را اجرا کنید، به شما پیغام NO, this is not refrence را میدهد! چرا که هر دو شئ به صورت جداگانه در حافظهی Heap ذخیره شدهاند و هیچکدام به دیگر ارجاعی ندارد و به اصطلاح با هم ارتباطی ندارند و اگر ما بیایم به این شکل عمل کنیم، آنوقت دیگر یک ارجاع داریم به یک شئ مشخص؛ class WebsiteAndPlatform { var website_name, platform_name : String init(web_name : String, platform : String) { self.website_name = web_name self.platform_name = platform } } let _website_and_platform_one = WebSiteAndPlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _website_and_platform_two = _website_and_platform_one if _website_and_platform_one === _website_and_platform_two { print("This is refrence!") }else { print("No,this is not refrence!") } به جای ایجاد شئ جدید، همان شئ اول را به متغییر دوم انتساب میدهیم که در واقع الان دو شئ داریم که شئ دومی به شئ اولی اشاره میکند. یعنی اینکه الان با هم در ارتباط هستند و شئ دومی ارجاعیست به شئ اول؛ نتیجه خروجی هم This is refrence است. نامساوی بودن دو شئ ( ==! ) اگر دو شئ از یک مرجع نبودند، و هر کدام در حافظهای جداگانه نگهداری میشوند، نتیجه به صورت true و اگر دو شئ از یک مرجع بودند، نتیجه false خواهد بود. کاملا برعکس علامت ( === ). به مثال زیر دقت کنید: class WebsiteAndPlatform { var website_name, platform_name : String init(web_name : String, platform : String) { self.website_name = web_name self.platform_name = platform } } let _website_and_platform_one = WebSiteAndPlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") let _website_and_platform_two = WebSiteAndPlatform(web_name : "www.iostream.ir", platform : "www.fanoox.com") if _website_and_platform_one !== _website_and_platform_two { print("This is refrence!") }else { print("No,this is not refrence!") } مثال بالا هم که کاملا واضح است! اینکه اگر دو شئ با هم ارجاعی نداشتند، پس نتیجه true است و در غیر اینصورت اگر ارجاع داشتند، نتیجه false و شرط آخر اجرا خواهد شد که No, this is not refrence است. آپریتر ترِنِری ( Ternary Conditonal Operators ) سه قسمت دارد؛ مسئله/شرط مقدار اول مقدار دوم ابتدا شرط قرار خواهد گرفت و سپس به دنبال آن آپِریِتر ? و بعد از آن جواب اول که در صورت درست بودن شرط، برگشت داده میشود و علامت کالُن ( : ) بعد از جواب اول قرار میگیرد که در صورتی که نتیجه نادرست یا false باشد، مقدار بعد ( : ) برگشت داده میشود. به مثال زیر توجه کنید؛ let _website_name_and_platform_name : String = 2 > 1? "www.iostream.ir" : "www.fanoox.com" print("Result =>", _website_name_and_platform_name) // Output the www.iostream.ir در مثال بالا همانطور که مشاهده میکنید، ابتدا شرط یا مسئله قرار میگیرد و سپس مقدار بعد آپِریِتر ? و مقدار اول و دوم که با ( : ) از هم جدا میشوند. در این مثال نتیجه، www.iostream.ir است، چرا که ۲ بزرگتر از ۱ است و این کاملا منطقی است که نتیجهی true دارد. آپریتر دامِنه ( Range Operator ) بیشتر در حلقهها استفاده میشود و نحوهی کار آن را در جلسهی قبل توضیح داده شده است؛ for index_number_one in 0...20 { print(index_number_one, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 } for index_number_two in 0..<20 { print(index_number_two, separator : " ",terminator : "") // Output the number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 16 17 18 19 } آپریترهای منطقی ( Logical Operators ) شامل !،&&،|| هستند که بیشتر استفادهی آنها در حلقههاست، اما شما میتوانید در هر جایی از پروژهی خودتان که نیاز به آنها داشتید، استفاده کنید. نَقیض ( ! ) کار آن، برعکس کردن یا نقض کردن یک مقدار است که امکان دارد true یا false باشد. به عنوان مثال اگه مقدار متغییری true است و این آپِریِتر را در ابتدای آن مقدار قرار بدهید، خروجی برابر است با false. و همین مورد هم برعکس صدق میکند، یعنی اگر شما مقدار متغییری false داشتید، با گذاشتن این عبارت در ابتدای متغییر، نتیجه true خواهد شد؛ var isname_website_iostream : Bool = false print(!is_name_website_iostream) // Output the bool true isname_website_iostream = true print(!isname_website_iostream) // Output the bool false درست بودن دو یا چند شرط ( && ) اگر در شرط یا عبارتی بخواهیم دو شرط را بررسی کنیم که هر دو هم حتما باید درست ( true ) باشند از این آپِریِتر استفاده خواهیم کرد؛ let web_sitename, platform_name : String web_sitename = "www.iostream.ir" platform_name = "www.fanoox.com" if web_sitename == "www.iostream.ir" && platform_name == "www.fanoox.com" { print(web_sitename, platform_name) } else { print("None") } در قطعه کد بالا، هر دو شرط مبنی بر اینکه دو مقدار متغییر تعریف شده باید برابر با مقدار تعیین شده در شرط باشند تا مقادیر چاپ شوند. در غیر اینصورت با خروجی None روبرور خواهیم شد. درست بودن حداقل یک شرط ( || ) اگر یکی از شرطها در بین چندین شرط که برقرار است و به عبارتی نتیجه درست ( true ) داشته باشد، وارد بدنهی شرطه خواهد شد و دستورات را اجرا میکند. اگه تمامی شرطها نادرست ( false ) باشند، دستورات داخل بدنه اجرا نخواهند شد؛ var web_sitename, platform_name : String web_sitename = "www.iostream.ir" platform_name = "www.fanoox.com" if web_sitename == "www.iostream.ir" || platform_name == "www.fanoox.ir" { print(web_sitename, platform_name) } else { print("None") } در مثال بالا شرط دوم برقرار نیست! چرا که متغییر platform_name با مقدار سمت راست آن برابر نیست. اما از آنجایی که از ( || ) استفاده کردهایم، پس شرط اول درست بوده و دستورات داخل بدنهی شرط if اجرا خواهند شد. کلمات کلیدی continue,break,fallthrough کلمهی کلید continue اگر بخواهیم در یک حلقه در یک جایی به بعد دستورات اجرا نشوند و حلقه مقدار فعلی را نادیده بگیرد، از این کلمهی کلید کمک خواهیم گرفت؛ for index in 0...20 { if index == 5 { continue } print(index) } /* Output the number 0 1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 */ همانطور که در مثال بالا مشاهده میکنید، در حلقهی for شرط داخل حلقه بر این مبنا است که هر زمانی که متغییر index مساوی مقدار ۵ شد، به ادامهی دستورات پایان بده ( continue ) و مجدد حلقه را از سر بگیر. به همین خاطر است که عدد ۵ نمایش داده نشده است. کلمهی کلید break با این کلمهی کلید به راحتی میتوانید هر جایی از حلقه که دیگر نیازی نداشتید ادامه پیدا کنید، حلقه را متوقف یا به اصطلاح بشکنید!. با این کار دیگر حلقه تکرار نشده و دستورات بعد از حلقه اجرا خواهند شد؛ for index in 0...5 { if index == 2 { break } print(index) } /* Output the number 0 1 */ کلمهی کلید fallthrough شاید در جایی از دستور شرطی switch لازم داشتید که caseهای بعدی هم اجرا شوند. با این کلمهی کلیدی میتوانید این کار را انجام دهید؛ let _number : Int8 = 1 switch _number { case 2: print(2) case 1: print(1) fallthrough case 3: print(3) fallthrough default: print("None") } بعد از هر caseی که میخواهید اجرا شود باید این کلمهی کلیدی را قرار دهید. امیدوایم این جلسه هم مورد رضایت شما عزیزان قرار گرفته باشد.
-
آموزش زبان برنامهنویسی سوئیفت - جلسه سوم مواردی که در این جلسه یاد خواهید گرفت: انواع داده و حلقهها در زبان برنامهنویسی سوئیفت ما با انواعی از دادهها روبرو هستیم! طبق دیگر زبانهای برنامهنویسی نوع دادههای پرکاربرد را معرفی خواهیم کرد و همچنین دیگر نوعهای داده را در ادامه بازگو میکنیم که شما با دقت بتوانید در پروژههای خودتان نوعهای دادهی مناسب پروژهی خودتان را انتخاب کنید. همچنین باید در نظر داشته باشید که در هر پروژهی نرمافزاری به کار بردن نوعهای دادهای که اصلا شاید مناسب قسمتی از پروژه یا نیازی به آن نباشد و با نوع دادهای دیگر مسئله بهتر و بهینهتر حل شود و استفاده کنید، استاندارد پروژهی شما کاهش پیدا خواهد کرد و مطمعن هستم که شما دوست ندارید نرمافزاری غیراستاندارد و بهینه داشته باشید! بنابراین در انتخاب نوعهای داده در پروژههای خودتان نهایت دقت را به خرج دهید! چه کسی دوست ندارد که پروژهای کارآمد و بهینه داشته باشد که هر توسعه دهندهای با دیدن نظم و بهینه بودن پروژهاش، آن را تحَسین کند؟!. درمورد حلقهها هم یک توضیح مختصر خواهیم داد و بعد به سراغ کُدنویسی خواهیم رفت که مطمئنن قسمت هیجانی برای هر برنامهنویسی است?. همهی ما در برنامهنویسی نیاز داریم که چندین خط کد رو بنویسم تا در نهایت برنامهی ما به خوبی اجرا شود، البته اگه بقیهی قسمتهای کدهایتان به درستی کار کند! اما همین چند خط کد رو مثلا چاپ اعداد ۰ تا ۱۰ در نظر بگیرید؛ print(0) print(1) print(2) print(3) print(4) print(5) print(6) print(7) print(8) print(9) print(10) احتمالا با خودتان میگوید چه برنامهنویسی داریم که چنینکاری میکند؟! این همه کد! حالا فکر کنید از ۰ تا ۱۰۰۰ باید به همین شکل بنویسید! کاری با خطوط کدها و حتی منطقی بودن آن هم نداریم! اما واقعا حوصله، زمان و انرژی باارزشتان چه میشود؟ پس راهحل چیست؟ درست حدس زدید! حلقهها! این مسئله را به سادگی و زیبایی هر چه تمامترحل کردند. پس مثال بالا را با یک حلقه مینویسیم؛ for index in 0...5 { print(index) // Output => 0,1,2,3,4,5 } فقط با چندین خط کد این مسئله برطرف شد! حال شما میتوانید به جای عدد ۵، عدد ۱۰۰۰ یا بیشتر را قرار بدهید. پس متوجه شدید که کاربرد حلقهها در برنامهنویسی چقدر مهم و حیاتی هستند! که برای تکرار دستوراتی هستند که دادههای زیادی به صورت مستقیم یا غیر مستقیم در برنامه مورد استفاده قرار میگیرد و عملا بدون حلقهها باید کدهای زیادی بنویسید تا این دادهها نمایش داده شوند!. انواع داده در سوئیفت، ما با انواعی از داده سر و کار داریم که عبارتاند از: انواع دادهی صحیح و اعشاری Int۸؛ نوع دادهی عددی ۸بیت است، به این صورت که فقط توانایی ذخیره ۱بایت را دارد. و مقادیر ۱۲۷ تا ۱۲۷- را پوشش میدهد. UInt8؛ این نوع داده عددی فقط و فقط یک مقدار از ۰ تا ۲۵۵ را پوشش خواهد داد و ۱بایت است. که در واقع کوتاه شدهی نام Unsigned Integer، است که به معنای نوع بدون علامت ( - ) است. Int۳۲؛ این نوع داده ۴بایتی ( ۴ * ۸ ) است، و مقداری از ۲۱۴۷۴۸۳۶۴۷ تا ۲۱۴۷۴۸۳۶۴۷- را پوشش میدهد. UInt32؛ مانند UInt8، است، با این تفاوت که فقط مقادیر صحیح بدون علامت ( - ) را قبول میکند و ۴بایت است. از مقدار ۰ تا ۴۲۹۴۹۶۷۲۹۵ را پوشش میدهد. Int۶۴؛ مقداری بیشتری در خود ذخیره میکند و در نتیجه تعداد بایتهای بیشتری را هم از حافظه اشغال میکند! که ۸بایت است. یعنی اینکه مقدار عددی تا ۲۰ رقم عدد صحیح با علامت ( + ) و بدون علامت ( - ) را ذخیره میکند. از مقدار ۹۲۲۳۳۷۲۰۳۳۶۸۵۴۷۷۵۸۰۸ تا ۹۲۲۳۳۷۲۰۳۳۶۸۵۴۷۷۵۸۰۸- را پوشش میدهد. UInt۶۴؛ مانند Int64 است که مقدار بیشتری ذخیره میکند که فقط شامل اعداد صحیح بدون علامت ( - ) است و ۸بایتی. از مقدار ۰ تا ۱۸۴۴۶۷۴۴۰۷۳۷۰۹۵۵۱۶۱۵ را پوشش میدهد ( دو برابر Int64 ). Float: این نوع دادهی اعشاری است و ۴بایتی. مقادیر اعشاری از ۱.۲E-38 تا ۳.۴E-38 را پوشش میدهد ( تا ۶ رقم اعشار ). البته این اعدا و این نوع نوشتاری، نمادهای علمی هستند!. Double: در این نوع اعشاری یک تفاوت وجود دارد و آن اینکه فضای بیشتری را در اختیارمان میگذارد و همینطور دقت بالایی را هم در محاسبات به همراه دارد. ۸بایتی است و از مقدار ۲.۳E-308 تا ۱.۷E+308 را پوشش میدهد ( تا ۱۵ رقم اعشار ). برای هر کدام یک مثال خواهیم زد؛ var int_8_byte : Int8 = -50 print(int_8_byte) var uint_8_byte : UInt8 = 50 print(uint_8_byte) var int_32_byte : Int32 = -560 print(int_32_byte) var uint_32_byte : UInt32 = 560 print(uint_32_byte) var int_64_byte : Int64 = -1567 print(int_64_byte) var uint_64_byte : UInt64 = 1567 var float : Float = 18.5 print(float) var double : Double = 19.75 print(double) این قطعه کدها را در اِدیتور ( Editor ) یا IDE خودتان وارد و اجرا کنید تا نتیجه را بصورت زنده مشاهد کنید ( لطفا کُپی و پیست نکنید! ) خودتان بنویسید تا هم لذت کدنویسی را بچشید و هم اینکه بهتر یاد بگیرید. در این میان، دقت کنید که نوع دادهی خودتان را به درستی در پروژههای نرمافزاری استفاده کنید و طبق نیاز نرمافزار خود از دادهی مورد نیاز استفاده کنید. به عنوان مثال، یک بخشی از برنامهی شما نیاز به دادهای به اندازهی ۸بایت دارد، ولی شما میآید و یک دادهی ۶۴بایتی تعریف میکنید برای آن! با اینکار حافظهی سیستم شما و آن کسی که نرمافزار شما را اجرا خواهد کرد، احتمالا صدای فَن آن در خواهد آمد! پس دقت کنید. نوع دادهی بُولیَن ( Boolean ) دو مقدار True یا False دریافت میکند. از این نوع داده بیشتر در دستورات شرطی استفاده میشود و بخشهایی از برنامه که نیاز به بررسی و درستی یا نادرستی یک عبارت دارد. نحوهی تعریف و استفاده از آن هم به این شکل است؛ let _boolean : Bool = true // Or false print(_boolean) در این تعریف شما میتوانید با تعریف نوع دادهی Bool و سپس مقدار به آن، از آن در قسمتهای مختلف برنامه استفاده کنید. نوع دادههای رشتهای و کارکتری String؛ یک دنبالهای از رشته ( همان متن ) را در خود ذخیره میکند؛ let _web_site_iostream : String = "www.iostream.ir" print(_web_site_iostream) Character؛ فقط و فقط یک کارکتر را قبول میکند( به جز کارکترهای کنترلی )؛ let _character : Character = "i" let _character_control : Character = "\n" print(_character) // Output => i print(_character_control) // Output => new line همانطور که مشاهده کردید، چندین نوع داده در زبان برنامهنویسی سوئیفت وجود دارد که شما باید با توجه به پروژهی خودتان از آنها در جای مناسب استفاده کنید. حلقهها و انواع آن حلقهها در سوئیفت به طور متفاوتی تعریف میشوند، اما همهی آنها کار یکسانی انجام میدهند! یعنی تکرار دستورات! حلقهی اول که قصد معرفی آن را داریم، for است؛ for index in 0...5 { print(index) } در این تعریف همانطور که مشاهده میکنید، با تعریف کلمهی کلید for و بعد از آن یک نام دلخواه و معنیدار، برای اینکه مقادیر هر بار در آن ذخیره شوند ( در واقع نقش یک متغییر را بازی میکند ) و بعد کلمهی کلید in قرار میگیرد و در نهایت باید یک رِنج ( بازه ) مشخص از یک عدد تا یک عدد دیگر انتخاب کنیم که بین اینها با سه نقط ( ... ) از هم جدا میشوند! این به این معنی است که در این تعریف عدد اولی که تعیین میشود، تا عدد دوم به صورت کامل در index ذخیره خواهند شد و هیچ گونه کم و زیادی صورت نمیگیرد!. اما اگر بخواهیم یک عدد کمتر و یا در واقع یک تکرار کمتر داشته باشیم از این تعریف استفاده میکنیم؛ for index in 0..<5 { print(index) } در این صورت با آپریتر > ( کوچکتر ) میتوانیم یک عدد و در واقع یک تکرار کمتر داشته باشیم. اگر بخواهیم درمورد آرایه که در جلسات بعد دربارهی آنها صحبت خواهیم کرد، یک مثال بزنیم، به این صورت است؛ let _array_number = [10,20,30,40] for index in _array_number { print(index) } همانطور که میبینید، تعریف و استفاده از حلقهی for ساده و آسان است. حلقهی while، حلقهی دومی است که به معرفی آن خواهیم پراخت. این حلقه به این صورت تعریف خواهد شد؛ var number : Int8 = 0 while (number < 10) { print(number) number += 1 } در حلقه و در قسمت شرط آن شما میتوانید هر شرطی را که باعث ورود به بدنهی حلقه ( {} ) شود، تعریف کنید. کلمهی کلید while در ابتدا تعریف میشود و سپس شرطی را که مدنظرتان است، تعریف میکنید ( در بین دو پرانتز ) و سپس در بدنه شرط، دستورات خود را مینویسید. در نهایت، حلقهی آخر، حلقهی repeat استکه کارکردآن دقیقا همانند حلقهی do, while در سایر زبانهای برنامهنویسی است! نحوهی تعریف و استفاده از آن هم به این شکل است؛ var repeat : Int8 = 0 repeat { print(repeat) repeat += 1 } while repeat < 1 در این حلقه، بدنهی حلقه که شامل دستورات هستند ابتدا اجرا میشود و سپس شرط بررسی میشود! درست همانند do, while. این حلقه با کلمهی کلید repeat تعریف شده و سپس در بین آکولادها ( {} ) دستورات نوشته خواهند شد و بعد از آخرین آکولاد ( { ) جلوی آن و یا بعد آن کلمهی کلید while و سپس شرط را مینویسم. فقط توجه داشته باشید که while در اینجا نیازی به پرانتز ندارد!. البته این دستور فقط یک بار اجرا خواهد شد! چرا که متغییر repeat کوچکتر از ۱ نیست، بزرگتر از آن هم نیست و در واقع مساوی است ( مقدار repeat در همان ابتدا اول یک بار افزایش ( repeat =+ 1 ) داده میشود و مقدار ۱ را درون خود ذخیره میکند ). پس شرط نادرست ااست و حلقه دیگر اجرا نخواهد شد. نکته؛ دقت کنید که در تمامی حلقهها نیاز به آکولاد باز و بسته برای تعریف دستورات است و شما نمیتوانید بدون تعریف این آکولادها کدهای خودتان را بنویسید! پس این مورد را دقت کنید. به جزء حلقهی while دیگر حلقهها نیازی به پرانتز () برای تعریف شروط ندارند. امیدواریم که این جلسه هم مورد رضایت شما عزیزان قرار گرفته باشد.
-
پس با این حساب، با استفاده از کلید واژههای ذکر شده، میتونیم عملا تاییدهی استفاده از اطلاعات شئ MessageBox یا استفاده شئ از اطلاعات کتابخانهی دیگه رو صادر کنیم. امیدوارم که این بیانیهی من از اطلاعات شما درست باشه، اگه نیست، بیشتر فکر میکنم و اگه متوجه نشدم، لطف بکنید و کمی سادهتر برای بنده توضیح بدید. ممنون از محبتتون.