<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های مهدی یونسی</title>
        <link>https://virgool.io/feed/@younesi</link>
        <description>توسعه دهنده Back-End</description>
        <language>fa</language>
        <pubDate>2026-04-15 04:35:39</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/18539/avatar/Xg4tz1.jpg?height=120&amp;width=120</url>
            <title>مهدی یونسی</title>
            <link>https://virgool.io/@younesi</link>
        </image>

                    <item>
                <title>آرایه و Slice در گولنگ</title>
                <link>https://virgool.io/golangpub/array-and-slices-in-golang-l6ye1tbzuckj</link>
                <description>آرایهآرایه مجموعه ای از عناصر است که به یک نوع تعلق دارند. به عنوان مثال، مجموعه اعداد صحیح 5، 8 ، 9 ، 79 و 76 یک آرایه را تشکیل می دهد. تریکب کردن مقادیر از انواع مختلف  به عنوان مثال، یک آرایه که هم رشته دارد و هم عدد صحیح، در Go مجاز نیست.اندازه آرایه کاملا مشخص بوده به طوری که این مقدار در زمان کامپایل باید ثابت باشد. تعریف آرایهیک آرایه به نوع [n] T تعلق دارد. n تعداد عناصر موجود در یک آرایه را نشان می دهد و T نوع هر عنصر را نشان می دهد. تعداد عناصر n نیز قسمتی از نوع آن است (در ادامه با جزئیات بیشتری در این مورد بحث خواهیم کرد)روش های مختلفی برای اعلام آرایه ها وجود دارد. باهم تک تک آنها را بررسی می کنیم.func main() {  
    var a [3]int //int array with length 3
    fmt.Println(a)
}عبارت var a [3] int یک آرایه صحیح را به طول ۳ تعریف می کند. به همه عناصر یک آرایه به طور خودکار مقدار صفر نوع آرایه اختصاص می یابد. در این حالت a یک آرایه صحیح است و از این رو  به تمام عناصر a، مقدار صفر int که  0 است اختصاص می یابد. خروجی اجرای دستور پرینت برنامه فوق چنین خواهید بود: [0 0 0]ایندکس آرایه با ۰ شروع می شود و ۱- آخرین ایندکس آن می باشد. اگر بخواهیم به آرایه مثال بالا مقدار  اساین کنیم، چنین عمل می کنیم:var a [3]int //int array with length 3
 a[0] = 12 // array index starts at 0
 a[1] = 78
 a[2] = 50
 fmt.Println(a)خروجی قطعه کد فوق:[12 78 50]می تواتیم برای تعریف آرایه ها از نوع میانبر آن به صورتshort hand declaration (یعنی روش کوتاه) عمل کنیم.بدین صورت که می بینید:a := [3]int{12, 78, 50}                 // short hand declaration to create array نیازی نیست که در هنگام تعریف آرایه به شکل بالا همه عناصر یک آرایه مقدار داده شود.package main
import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    a := [3]int{12} 
    fmt.Println(a)
}در برنامه فوق در خط شماره ۸ a: = [3] int {12} آرایه ای به طول ۳ را اعلام می کند اما فقط با  مقدار ۱۲ پر می شود. ۲ خانه باقی مانده به طور خودکار 0 تعیین می شود. خروجی قطعه کد فوق:[12 0 0]نکته‌ای که باید بهش اشاره کرد اینه که مقدار دادن به خونه‌ای از آرایه که  وجود نداره باعث ایجاد خطا می شود.نکته: جهت راحتی کار میشه به جای عدد  ازسه نقطه ... استفاده کرد با این  قابلیت در زمان کامپایل سایز آرایه توسط مقادیر Initialize شده حساب می‌شود:a := [...]int{2, 9, 5} //... makes the compiler determine the lengthاندازه آرایه بخشی از نوع آن است. از این رو [5] int و [25] int انواع متمایزی هستند. به همین دلیل، اندازه آرایه ها قابل تغییر نیست. نگران این محدودیت نباشید زیرا slice ها به کمک ما می آیند.آرایه ها value type هستندآرایه ها در Go انواع مقداری هستند(value types) و انواع مرجعی (reference types) نیستند. این به این معنی است که وقتی آنها به یک متغیر جدید اختصاص می یابند، یک کپی از آرایه اصلی به متغیر جدید اختصاص می یابد. اگر تغییراتی در متغیر جدید ایجاد شود، در آرایه اصلی منعکس نمی شود.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]string{&amp;quotTEH&amp;quot, &amp;quotMHD&amp;quot, &amp;quotAWZ&amp;quot, &amp;quotIFN&amp;quot, &amp;quotSYZ&amp;quot}
    b := a // a copy of a is assigned to b
    b[0] = &amp;quotADU&amp;quot
    fmt.Println(&amp;quota is &amp;quot, a)
    fmt.Println(&amp;quotb is &amp;quot, b) 
}در برنامه فوق در خط شماره ۷، یک نسخه از a به b اختصاص داده شده است. در خط شماره ۸ اولین عنصر b به ADU تغییر کرده ولی این در آرایه اصلی (همان a) منعکس نشده است. a is [TEH MHD AWZ IFN SYZ]  
 b is [ADU MHD AWZ IFN SYZ]به همین علت وقتی آرایه ها به عنوان پارامتر به توابع منتقل می شوند، آنها از نظر مقدار(passed by value) منتقل می شوند و آرایه اصلی بدون تغییر می ماند. package main

import &amp;quotfmt&amp;quot

func changeLocal(num [5]int) {  
    num[0] = 55
    fmt.Println(&amp;quotinside function &amp;quot, num)

}
func main() {  
    num := [...]int{5, 6, 7, 8, 8}
    fmt.Println(&amp;quotbefore passing to function &amp;quot, num)
    changeLocal(num) //num is passed by value
    fmt.Println(&amp;quotafter passing to function &amp;quot, num)
}در برنامه فوق در خط شماره ۱۳   آرایه num در واقع به صورت pass by value به تابع changeLocal منتقل می شود وبه همین مقادیر اصلی آن بعد صدا زدن آرایه هیچ تغییری نخواهد کرد.before passing to function  [5 6 7 8 8]  
 inside function  [55 6 7 8 8]  
 after passing to function  [5 6 7 8 8]طول یک آرایهطول آرایه با پاس دادن  آرایه به عنوان پارامتر به تابع len پیدا می شود.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    fmt.Println(&amp;quotlength of a is&amp;quot,len(a))
}خروجی برنامه فوق بدین صورت می باشد:length of a is 4تکرار (iterate) روی عناصر آرایه ها همانطور که انتظار می رود میتوان از حلقه for می توان برای تکرار عناصر آرایه استفاده کرد.package main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    for i := 0; i &lt; len(a); i++ { //looping from 0 to the length of the array
        fmt.Printf(&amp;quot%d th element of a is %.2f\n&amp;quot, i, a[i])
    }
}برنامه فوق از یک حلقه for برای تکرار عناصر آرایه از شاخص 0 تا طول آرایه منهای یک استفاده می کند. خروجی کد فوق بدین صورت می باشد:0 th element of a is 67.70  
1 th element of a is 89.80  
2 th element of a is 21.00  
3 th element of a is 78.00گولنگ با استفاده از range روشی بهتر و مختصر برای تکرار در یک آرایه ارائه می دهد. range هم ایندکس و هم مقدار آن ایندکس را برمی گرداند. بیایید کد بالا را با استفاده از range بازنویسی کنیم و همچنین مجموع تمام عناصر آرایه را کنیمpackage main

import &amp;quotfmt&amp;quot

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    sum := float64(0)
    for i, v := range a {//range returns both the index and value
        fmt.Printf(&amp;quot%d the element of a is %.2f\n&amp;quot, i, v)
        sum += v
    }
    fmt.Println(&amp;quot\nsum of all elements of a&amp;quot,sum)
}خط شماره  کد بالا for i, v := range a حالت range  حلقه for است. هم ایندکس و هم مقدار آن شاخص را برمی گرداند. مقادیر را چاپ می کنیم و همچنین مجموع تمام عناصر آرایه a را محاسبه می کنیم. خروجی برنامه:0 the element of a is 67.70  
1 the element of a is 89.80  
2 the element of a is 21.00  
3 the element of a is 78.00

sum of all elements of a 256.5درصورتی که فقط مقدار می خواهید و می خواهید ایندکس را نادیده بگیرید، می توانید این کار را با جایگزینی متغیر ایندکس با شناسه _ خالی انجام دهید.for _, v := range a { //ignores index  
 }  حلقه for فوق ایندکس را نادیده می گیرد. به همین ترتیب مقدار نیز قابل چشم پوشی است. (خاطرتان حتما هست که در گولنگ اگر از متغیری که تعریف کردید استفاده نکنید با خطا مواجه می شوید. پس این نادیده گرفتن متغیرها کاملا طبیعی می باشد)آرایه های چند بعدیآرایه هایی که ما تاکنون ایجاد کرده ایم همه تک بعدی هستند. ایجاد آرایه های چند بعدی امکان پذیر است.package main

import (  
    &amp;quotfmt&amp;quot
)

func printarray(a [3][2]string) {  
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf(&amp;quot%s &amp;quot, v2)
        }
        fmt.Printf(&amp;quot\n&amp;quot)
    }
}

func main() {  
    a := [3][2]string{
        {&amp;quotlion&amp;quot, &amp;quottiger&amp;quot},
        {&amp;quotcat&amp;quot, &amp;quotdog&amp;quot},
        {&amp;quotpigeon&amp;quot, &amp;quotpeacock&amp;quot}, //this comma is necessary. The compiler will complain if you omit this comma
    }
    printarray(a)
    var b [3][2]string
    b[0][0] = &amp;quotapple&amp;quot
    b[0][1] = &amp;quotsamsung&amp;quot
    b[1][0] = &amp;quotmicrosoft&amp;quot
    b[1][1] = &amp;quotgoogle&amp;quot
    b[2][0] = &amp;quotAT&amp;T&amp;quot
    b[2][1] = &amp;quotT-Mobile&amp;quot
    fmt.Printf(&amp;quot\n&amp;quot)
    printarray(b)
}در برنامه فوق در خط شماره ۱۷ آرایه رشته ای دو بعدی a با استفاده از سینتکس short hand (که بالاتر توضیح دادیم)اعلام شده است.(comma در انتهای خط شماره 20 لازم است) آرایه دو بعدی دیگر به نام b در سطر شماره ۲۳ تعریف می شود  و string ها برای هر ایندکس یکی یکی به آن اضافه می شوند. این روش دیگری برای مقداردهی اولیه آرایه دو بعدی است است. فانکشن printarray در خط شماره ۷ برای چاپ محتویات آرایه های  دوبعدی از دو حلقه range استفاده می کند. برنامه فوق چاپ خواهد کرد:lion tiger  
cat dog  
pigeon peacock 

apple samsung  
microsoft google  
AT&amp;T T-Mobileبه نظرم در مورد آرایه ها تا اینجا کافیه! موافقید !؟  اگرچه آرایه ها به اندازه کافی انعطاف پذیر به نظر می رسند اما با محدودیت طول ثابت ارائه می شوند. افزایش طول یک آرایه امکان پذیر نیست. این جایی است که slice ها وارد بازی می شوند. در واقع در Go اسلایس ها خیلی رایج تر از آرایه ها هستند. در ادامه آنها را توضیح می دهیم. اسلایس (slice) در گولنگیک slice در واقع یک wrapper راحت، انعطاف پذیر و قدرتمند برای  آرایه است. slice ها به خودی خود هیچ داده ای ندارند. آنها فقط ارجاعات به آرایه های موجود هستند.ایجاد یک sliceیک slice با عناصر نوع T با [] T نشان داده می شودpackage main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    a := [5]int{76, 77, 78, 79, 80}
    var b []int = a[1:4] //creates a slice from a[1] to a[3]
    fmt.Println(b)
}سینتکس a[start:end] اسلایسی از آرایه a ایجاد می کند که از ایندکس start می شود تا ایندکس end-1. بنابراین در خط شماره 9 از برنامه فوق  [4: 1] نمایش آرایه a را با شروع از ایندکس های 1 تا 3 ایجاد می کند. از این رو اسلایس b دارای مقادیر [ 79 78 77 ] است. به یک روش  دیگر هم برای ایجاد یک slice نگاه کنیم.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    c := []int{6, 7, 8} //creates and array and returns a slice reference
    fmt.Println(c)
}در برنامه فوق در خط شماره ۹، c: = [] int {6، 7، 8} آرایه ای با ۳ عدد صحیح ایجاد می کند و یک reference اسلایس را که در c ذخیره شده است برمی گرداند.تغییر یک sliceیک اسلایس به خودی خود هیچ داده ای ندارد بلکه  فقط فقط رفرنسی نمایشی به آرایه زمینه ای است. هرگونه تغییری که در slice ایجاد شود، در آرایه زیرین منعکس خواهد شد.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println(&amp;quotarray before&amp;quot,darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println(&amp;quotarray after&amp;quot,darr) 
}در خط شماره ۹ برنامه فوق، از شاخص های 2 ، 3 ، 4 آرایه dslice ایجاد می کنیم. حلقه for مقدار این ایندکس ها را یکی افزایش می دهد. وقتی آرایه را بعد از حلقه for چاپ می کنیم، می توانیم ببینیم که تغییرات slice در آرایه منعکس شده است. خروجی برنامه:array before [57 89 90 82 100 78 67 69 59]  array after [57 89 91 83 101 78 67 69 59]  می بینید که با توجه به تغییرات اسلایس مقادیر آرایه اصلی هم تغییر پیدا کرده اند. مقادیر ایندکس های2، 3 و 4 هر کدام یکی بیشتر شده اند. (91, 83, 101)هنگامی که تعدادی از اسلایس ها آرایه اصلی یکسانی دارند، تغییراتی که هر یک ایجاد می کند در آرایه منعکس می شود.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    numa := [3]int{78, 79 ,80}
    nums1 := numa[:] //creates a slice which contains all elements of the array
    nums2 := numa[:]
    fmt.Println(&amp;quotarray before change 1&amp;quot,numa)
    nums1[0] = 100
    fmt.Println(&amp;quotarray after modification to slice nums1&amp;quot, numa)
    nums2[1] = 101
    fmt.Println(&amp;quotarray after modification to slice nums2&amp;quot, numa)
}در خط شماره ۹ در numa [:] مقادیر شروع و پایان وجود ندارد. مقادیر پیش فرض برای شروع و پایان به ترتیب 0 و len (numa) است. هر دو برش nums1 و nums2 یک آرایه مشترک دارند. خروجی برنامه:array before change 1 [78 79 80]  
array after modification to slice nums1 [100 79 80]  
array after modification to slice nums2 [100 101 80]از خروجی واضح است که وقتی اسلایس ها آرایه یکسانی دارند. تغییرات ایجاد شده در اسلایس در آرایه منعکس می شود.طول و ظرفیت یک اسلایس طول(length) یک slice تعداد عناصر موجود در آن است و ظرفیت(capacity) slice تعداد عناصر موجود در آرایه زیرین است که از نمایه ای که برش از آن ایجاد می شود شروع می شود.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    fruitarray := [...]string{&amp;quotapple&amp;quot, &amp;quotorange&amp;quot, &amp;quotgrape&amp;quot, &amp;quotmango&amp;quot, &amp;quotwater melon&amp;quot, &amp;quotpine apple&amp;quot, &amp;quotchikoo&amp;quot}
    fruitslice := fruitarray[1:3]
    fmt.Printf(&amp;quotlength of slice %d capacity %d&amp;quot, len(fruitslice), cap(fruitslice)) //length of fruitslice is 2 and capacity is 6
}در برنامه فوق ، fruitslice از شاخص 1 و 2 fruitarray ایجاد می شود. از این رو طول fruitslice برابر ۲ است. طول آرایه fruitarray برابر ۷ برابر است. برنج میوه از شاخص 1 آرایه ایجاد شده است. از این رو ظرفیت میوه میوه تعداد عناصر موجود در مجموعه میوه ای است که از شاخص 1 یعنی نارنجی شروع می شود و این مقدار 6 است. از این رو ظرفیت میوه میوه 6 است. برنامه طول قطعه 2 ظرفیت 6 را چاپ می کند. یک قطعه را می توانید مجدداً به ظرفیت خود برش دهید. هر چیزی فراتر از آن باعث می شود برنامه خطای زمان اجرا ایجاد کند.ایجاد اسلایس ها با استفاده از فانکشن makeاز سینتکس func make ([] T ، len ، cap) [] T می توان با پاس دادن نوع، طول و ظرفیت یک  slice ایجاد کرد. پارامتر ظرفیت(cap) اختیاری است و به طور پیش فرض نسبت به طول(len) انجام می شود. تابع make یک آرایه ایجاد می کند و یک slice که به آرایه اشاره می کند را برمی گرداند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    i := make([]int, 5, 5)
    fmt.Println(i)
}هنگام ایجاد یک slice، به طور پیش فرض مقادیر zero یا صفر (برای مثال برای نوع int مقدار 0) می شوند. در برنامه فوق خروجی [0 0 0 0 0] تولید خواهد شد.اضافه کردن مقدار جدید به یک sliceممکن است یک سوال برای شما پیش بیاید. اگر slice ها توسط آرایه ها پشتیبانی می شوند و آرایه ها نیز دارای طول ثابت هستند، پس چگونه یک slice دارای طول پویا است؟  خوب آنچه در اصل اتفاق می افتد این است، وقتی عناصر جدیدی به slice اضافه می شوند، یک آرایه جدید ایجاد می شود. عناصر آرایه موجود در این آرایه جدید کپی شده و رفرنس slice جدیدی برای این آرایه جدید بازگردانده می شود. ظرفیت slice جدید اکنون دو برابر slice قدیمی است. خیلی باحاله نه ؟ :) برنامه زیر همه چیز را روشن می کند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    cars := []string{&amp;quotFerrari&amp;quot, &amp;quotHonda&amp;quot, &amp;quotFord&amp;quot}
    fmt.Println(&amp;quotcars:&amp;quot, cars, &amp;quothas old length&amp;quot, len(cars), &amp;quotand capacity&amp;quot, cap(cars)) //capacity of cars is 3
    cars = append(cars, &amp;quotToyota&amp;quot)
    fmt.Println(&amp;quotcars:&amp;quot, cars, &amp;quothas new length&amp;quot, len(cars), &amp;quotand capacity&amp;quot, cap(cars)) //capacity of cars is doubled to 6
}در برنامه فوق، ظرفیت اسلایس cars در ابتدا ۳ است. ما در خط شماره ۱۰ عنصر جدید را به cars اضافه می کنیم و slice برگردانده شده توسط append(cars, &quot;Toyota&quot;) دوباره به cars اختصاص دهید. اکنون ظرفیت cars دو برابر شده و ۶ می شود. cars: [Ferrari Honda Ford] has old length 3 and capacity 3  
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6پاس دادن یک اسلایس به یک فانکشن به عنوان آرگومان قبلا در مورد struct ها در این پست صحبت کردیم. اسلایس ها رو می توانیم مثل یک struct به صورت زیر در نظر بگیریم.type slice struct {  
    Length        int
    Capacity      int
    ZerothElement *byte
}یک ساختار slice شامل length، capacity و pointer به عنصر صفر آرایه است. هنگامی که یک برش به یک تابع منتقل می شود، با اینکه با مقدار (pass by value) پاس داده می شود ولی نشانگر به همان آرایه زیرین ارجاع می کند(اشاره می کند). از این رو وقتی یک اسلایس به عنوان پارامتر به یک تابع پاس داده می می شود، تغییرات ایجاد شده در داخل تابع نیز در خارج از تابع قابل مشاهده است. بیایید برنامه ای برای بررسی این موضوع بنویسیم.package main

import (  
    &amp;quotfmt&amp;quot
)

func subtactOne(numbers []int) {  
  for i := range numbers {
    numbers[i] -= 2
    }
}

func main() {  
    nos := []int{8, 7, 6}
    fmt.Println(&amp;quotslice before function call&amp;quot, nos)
    subtactOne(nos)                               //function modifies the slice
    fmt.Println(&amp;quotslice after function call&amp;quot, nos) //modifications are visible outside
}فراخوانی فانکشن در خط شماره ۱۷ برنامه فوق هر یک از عناصر اسلایس را 2 تا کم میکند. وقتی قطعه بعد از فراخوانی فانکشن چاپ می شود، این تغییرات قابل مشاهده هستند. slice before function call [8 7 6]  slice after function call [6 5 4]  برش های چند بعدیمشابه آرایه ها، اسلایس ها می توانند ابعاد مختلفی داشته باشند.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
     pls := [][]string {
            {&amp;quotC&amp;quot, &amp;quotC++&amp;quot},
            {&amp;quotJavaScript&amp;quot},
            {&amp;quotGo&amp;quot, &amp;quotRust&amp;quot},
            }
    for _, v1 := range pls {
        for _, v2 := range v1 {
            fmt.Printf(&amp;quot%s &amp;quot, v2)
        }
        fmt.Printf(&amp;quot\n&amp;quot)
    }
}خروجی برنامه فوق:C    C++  
JavaScript  
Go    Rust  بهینه سازی حافظهاسلایس ها اشاره ای به آرایه اصلی دارند. تا زمانی که اسلایس در حافظه باشد، آرایه را نمی توان garbage collect کرد. وقتی صحبت از مدیریت حافظه می شود، این مورد ممکن است نگران کننده باشد. بیایید فرض کنیم که ما یک آرایه بسیار بزرگ داریم و ما علاقه مند هستیم که فقط قسمت کوچکی از آن را پردازش کنیم. برای این کار ما یک اسلایس از آن آرایه ایجاد می کنیم و پردازش را روی اسلایس انجام می دهیم. نکته مهمی که در اینجا باید به آن اشاره شود این است که آرایه همچنان در حافظه باقی می ماند زیرا این اسلایس به آن اشاره می کند.یکی از راه های حل این مشکل استفاده از تابع copy به صورت  func copy (dst، src [] T) int برای ایحاد کپی از آن اسلایس است. به این ترتیب می توانیم از برش جدید استفاده کنیم و آرایه اصلی می تواند از حافظه حذف شود.جمله پایانی: در صورتی که مطلب را دوست داشتید لایک ❤️ کنید یا نظرتان را از طریق کامنت برای من بنویسید.</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Thu, 09 Sep 2021 19:24:08 +0430</pubDate>
            </item>
                    <item>
                <title>ساختار یا struct در گولنگ چیست ؟</title>
                <link>https://virgool.io/golangpub/structs-in-golang-lmedjf9xijyz</link>
                <description>معرفییک struct (ساختار) به مجموعه‌ای از فیلدهای مرتب با هم که یک واحد منسجم (unit) را تشکیل می‌دهند اشاره دارد. به هر عضو از این unit یک فیلد field گفته می‌شود. ساختار یک نوع تعریف شده توسط کاربر  (user-defined) است که در مواردی  که منطقی باشد که داده ها را به جای مقادیر جداگانه در یک واحد قرار دهیم استفاده می شود.به عنوان مثال، یک کارمند دارای نام، نام خانوادگی و سن است. منطقی است که این سه ویژگی را در یک ساختار واحد به نام Employee گروه بندی کنید.نحوه تعریف استراکتtype Employee struct {  
    firstName string
    lastName  string
    age       int
}قطعه کد فوق یک type ساختار از ׄEmployee با زمینه های firstName ، LastName و age تعریف می کند. به ساختار Employee فوق به این دلیل named struct  نامیده می شود  که  نوع داده جدیدی به نام Employee با استفاده از  Employee ایجاد می کند.مقدار دهی اولیه قطعه کد زیر را ببینید، ساختار emp1 با تعیین مقدار برای هر نام فیلد تعریف می شود. هنگام اعلام نوع ساختار، لزوماً ترتیب فیلدها مانند ترتیب نام فیلدها نیست. در این مورد ما موقعیت فیلد lastName را تغییر داده و به انتها منتقل کرده ایم. این بدون مشکل کار خواهد کرد.package main

import (  
    &amp;quotfmt&amp;quot
)

type Employee struct {  
    firstName string
    lastName  string
    age       int
    salary    int
}

func main() {

    //creating struct specifying field names
    emp1 := Employee{
        firstName: &amp;quotAli&amp;quot,
        age:       25,
        salary:    500,
        lastName:  &amp;quotMehdi&amp;quot,
    }

    //creating struct without specifying field names
    emp2 := Employee{&amp;quotMehdi&amp;quot, &amp;quotAli&amp;quot, 29, 800}

    fmt.Println(&amp;quotEmployee 1&amp;quot, emp1)
    fmt.Println(&amp;quotEmployee 2&amp;quot, emp2)
} ساختار emp2 با حذف نام فیلدها تعریف می شود. در این حالت، لازم است که ترتیب فیلدها همان چیزی باشد که در  struct مشخص شده است. لطفاً از استفاده از این سینتکس خودداری کنید زیرا تشخیص اینکه کدام مقدار برای کدام قسمت است دشوار است. ما این قالب را در اینجا گفتیم تا بدانید که این نیز یک سینتکس معتبر است :)ایجاد استراکت anonymous  بدون ایجاد نوع داده جدید(تعریف نام برای struct)، می توان یک ساختار تعریف کرد. به این نوع از struct ها  anonymous (ناشناس) گفته می شود.package main

import (  
    &amp;quotfmt&amp;quot
)

func main() {  
    emp3 := struct {
        firstName string
        lastName  string
        age       int
        salary    int
    }{
        firstName: &amp;quotAli&amp;quot,
        lastName:  &amp;quotIrani&amp;quot,
        age:       49,
        salary:    50000,
    }

    fmt.Println(&amp;quotEmployee 3&amp;quot, emp3)
}متغیر emp3 از نوع  ساختار anonymous  تعریف شده است. همانطور که قبلاً اشاره کردیم، این ساختار ناشناس نامیده می شود زیرا فقط متغیر جدیدی ایجاد می کند و هیچ نوع struct جدیدی مانند named struct  را تعریف نمی کند. خروجی این برنامه :Employee 3 {Ali Irani 49 50000}دسترسی به فیلد های یک struct عملگر نقطه . برای دسترسی به فیلدهای  یک ساختار استفاده می شود.fmt.Println(&amp;quotFirst Name:&amp;quot, emp3.firstName) در برنامه فوق به فیلد firstName از ساختار emp3 دسترسی پیدا میکنیم.مقدار صفر(zero) یا تعریف نشده  یک ساختاروقتی یک ساختار تعریف می شود و به طور واضح با هیچ مقداری مقداردهی اولیه نمی شود، به فیلدهای ساختار به طور پیش فرض مقادیر صفر آنها اختصاص داده می شود.var emp4 Employee //zero valued struct
 fmt.Println(&amp;quotFirst Name:&amp;quot, emp4.firstName)
 fmt.Println(&amp;quotLast Name:&amp;quot, emp4.lastName)
 fmt.Println(&amp;quotAge:&amp;quot, emp4.age)
 fmt.Println(&amp;quotSalary:&amp;quot, emp4.salary)برنامه فوق emp4 را تعریف می کند اما با هیچ مقداری مقداردهی اولیه نمی شود. از این رو به firstName و lastName مقادیر صفر رشته ای که یک رشته خالی است &quot;&quot; اختصاص داده می شود و به age ، salary  مقادیر صفر  int که 0 است اختصاص داده می شود.  خروجی این برنامه :First Name:  
 Last Name:  
 Age: 0  
 Salary: 0همچنین می توان مقادیر را برای برخی از فیلدها مشخص کرد و بقیه را نادیده گرفت و مقدار بهشون نداد. در این حالت هم به فیلدهای نادیده گرفته شده مقادیر صفر اختصاص داده می شود.اشاره گرها (Pointers) به یک ساختارهمچنین می توان اشاره گر(pointer) برای یک ساختار را ایجاد کرد.emp5 := &amp;Employee{
        firstName: &amp;quotMehdi&amp;quot,
        lastName:  &amp;quotYounesi&amp;quot,
        age:       30,
        salary:    6000,
}
fmt.Println(&amp;quotFirst Name:&amp;quot, (*emp5).firstName) دقت کنید در برنامه فوق emp5 یک اشاره گر به ساختار Employee است . *emp5.firstName نحوه دستیابی به فیلد firstName از ساختار emp5 است. (میدونم پرانتزها رو نگذاشتم جون تو ویرگول هر کاری کردم درست الاین نشد)زبان Go به ما این امکان را می دهد تا از emp5.firstName به جای استفاده از استنباط صریح (همانند مدل بالا) برای دسترسی به فیلد firstName استفاده کنیم.فیلد های ناشناس (Anonymous)می توان با فیلدهایی که فقط یک نوع بدون نام فیلد در آن قرار دارند، struct را ایجاد کرد. این نوع فیلدها را فیلدهای anonymous می نامند. قطعه کد زیر یک  ساختار Person  ایجاد می کند که دارای دو فیلد ناشناس string و int است.type Person struct {  
    string
    int
}همانطور که می بینید فیلدهای ناشناس نام مشخصی ندارند اما به طور پیش فرض نام فیلد ناشناس نام نوع آن است. به عنوان مثال در مورد ساختار Person در بالا، اگر چه فیلدها ناشناس هستند، اما به طور پیش فرض آنها نام نوع فیلدها را می گیرند. بنابراین  ساختار Person دارای ۲ فیلد با  نام های string و int  است.p1 := Person{
        string: &amp;quotMehdi&amp;quot,
        int:    50,
}
fmt.Println(p1.string)
fmt.Println(p1.int)
خروجی:Mehdi  
 50ساختارهای Nestedاین امکان وجود دارد که مقدار فیلد struct به صورت struct تعریف شود که در این صورت به آنها ساختارهای تو در تو یا nested گفته می شود. در مثال زیر اطلاعات آدرس در ساختار اطلاعات خود شخص گنجانده شده است!type Address struct {  
    city  string
    state string
}

type Person struct {  
    name    string
    age     int
    address Address
}

func main() {  
    p := Person{
        name: &amp;quotNaveen&amp;quot,
        age:  50,
        address: Address{
            city:  &amp;quotChicago&amp;quot,
            state: &amp;quotIllinois&amp;quot,
        },
    }
}شاید سوال براتون پیش باید که حالا نحوه دسترسی بهاطلاعات آدرس در این ساختار nested چطور خواهد بود؟ خیلی راحت مثل حالت عادیp.address.city
// and
p.address.state یک سری فیلد داریم که بهشون میگن Promoted fields فیلدهایی که به یک فیلد ساختار ناشناس در یک ساختار تعلق دارند، فیلدهای promoted گفته می شود زیرا می توان به آنها دسترسی پیدا کرد انگار که به ساختار متعلق به فیلد anonymous  تعلق دارند. یعنی چی؟برای اینکار کافی بود که در مثال قبلی اسمی برای ساختار nested خود تعریف نکنیم. یعنی به صورت زیر:type Person struct {  
    name string
    age  int
    Address
}در قطعه کد فوق، Person ساختار دارای یک فیلد ناشناس Address است که یک ساختار است. اکنون فیلدهای Address یعنی city و state را فیلدهای ارتقا یافته (promoted) می نامند زیرا حالا می توان به گونه ای که مستقیماً در خود ساختار Person اعلام شده باشد به آنها دسترسی داشت.package main

import (  
    &amp;quotfmt&amp;quot
)

type Address struct {  
    city  string
    state string
}
type Person struct {  
    name string
    age  int
    Address
}

func main() {  
    p := Person{
        name: &amp;quotMehdi&amp;quot,
        age:  30,
        Address: Address{
            city:  &amp;quotIstanbul&amp;quot,
            state: &amp;quotAvcılar&amp;quot,
        },
    }

    fmt.Println(&amp;quotName:&amp;quot, p.name)
    fmt.Println(&amp;quotAge:&amp;quot, p.age)
    fmt.Println(&amp;quotCity:&amp;quot, p.city)   //city is promoted field
    fmt.Println(&amp;quotState:&amp;quot, p.state) //state is promoted field
} مقایسه برابری structهاساختارها از نوع value type هستند و اگر هر یک از فیلد های آنها قابل مقایسه باشد، قابل مقایسه هستند. وقتی دو متغیر از نوع struct با هم برابر هستند که تمام فیلدهای آن ها با هم برابر باشند.package main

import (  
    &amp;quotfmt&amp;quot
)

type name struct {  
    firstName string
    lastName  string
}

func main() {  
    name1 := name{
        firstName: &amp;quotSteve&amp;quot,
        lastName:  &amp;quotJobs&amp;quot,
    }
    name2 := name{
        firstName: &amp;quotSteve&amp;quot,
        lastName:  &amp;quotJobs&amp;quot,
    }
    if name1 == name2 {
        fmt.Println(&amp;quotname1 and name2 are equal&amp;quot)
    } else {
        fmt.Println(&amp;quotname1 and name2 are not equal&amp;quot)
    }

    name3 := name{
        firstName: &amp;quotSteve&amp;quot,
        lastName:  &amp;quotJobs&amp;quot,
    }
    name4 := name{
        firstName: &amp;quotSteve&amp;quot,
    }

    if name3 == name4 {
        fmt.Println(&amp;quotname3 and name4 are equal&amp;quot)
    } else {
        fmt.Println(&amp;quotname3 and name4 are not equal&amp;quot)
    }
}خروجی قطعه کد فوق:name1 and name2 are equal  
 name3 and name4 are not equalمتغیرهای struct در صورت داشتن فیلد هایی که قابل مقایسه نیستند، قابل مقایسه نخواهند بود.نتیجه گیریعالی! اکنون آماده استفاده از struct در گولنگ هستید. همه مبانی مانند اعلان، مقداردهی اولیه، ساختار و فیلدهای  anonymous و دسترسی به فیلد های ساختار را توضیح دادم. ما همچنین به چگونگی مقایسه دو struct نگاه کردیم و حتی ساختار تو در تو را اجرا کردیم. دیگه موردی برای یادگیری در مورد struct در گولنگ باقی نماند.با تشکر از شما برای خواندن این مطلب، لطفا نظرات و انتقادات خودتون  را کامنت کنید.</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Thu, 27 May 2021 00:11:09 +0430</pubDate>
            </item>
                    <item>
                <title>متدها در زبان GoLang</title>
                <link>https://virgool.io/golangpub/%D9%85%D8%AA%D8%AF%D9%87%D8%A7-%D8%AF%D8%B1-%D8%B2%D8%A8%D8%A7%D9%86-golang-vvbooi0ixsoy</link>
                <description>با سلامزبان گولنگ یک زبان OOP نیست و مفهومی با عنوان کلاس(class) که در آن نوع زبان ها هست رو نداره اما میتوانیم برای انواع نوع  داده یا همان (type)ها متد تعریف کنیم.متد در زبان گولنگ شباهت زیادی به فانکشن دارد، در واقع یک متد یک  فانکشن  با آرگومان receiver خاص هست.خب بهتره جهت یادآوری و هم درک بهتر موضوع رجوعی به بحث فانکش ها  داشته باشیم.func avg(x, y float64) float64 {
        return (x + y) / 2
}یک فانکشن میتواند هیچ یا چند آرگومان داشته باشد و توجه داشته باشید که بعد از تعریف آرگومان ها می توانیم نوع خروجی رو  رو هم مشخص می کنیم(اختیاری است) نوع آرگومان بعد از اسم آنها می‌آید و اگر مانند مثال بالا نوع همه آرگومان ها یکسان باشد می توانیم نوع را فقط برای آخرین مورد تعریف کنیم.فانکش ها در زبان گولنگ خصوصیات دیگری مانند  مقدار خروجی نام گذاری شده و چند خروجی را دارند که با توجه به موضوع اصلی مقاله نیاز به بررسی این موارد رو نمی بینم. خب برگردیم به سراغ متد هانوع receiver که در بالا اشاره کردیم بین کلمه  func  و نام تابع(MethodName) قرار میگیرد. ریسیور یک نام و نوع دارد:func (receiver Type) MethodName(parameterList) (returnTypes) { 
}در مثال  زیر متد show یک receiver از نوعauthor با نام a میگیرد و کارش این است که اطلاعات یک نویسنده رو نمایش دهند. package main
import &amp;quotfmt&amp;quot
// Author structure
type author struct {
    name      string
    branch    string
   particles int
   salary    int
}
// Method with a receive  of author type
func (a author) show() {
    fmt.Println(&amp;quotAuthor&#039;s Name: &amp;quot, a.name)
    fmt.Println(&amp;quotBranch Name: &amp;quot, a.branch)
    fmt.Println(&amp;quotPublished articles: &amp;quot, a.particles)
    fmt.Println(&amp;quotSalary: &amp;quot, a.salary)
}
// Main function
func main() {
    // Initializing the values of the author structure
res := author{
    name:      &amp;quotSona&amp;quot,
    branch:    &amp;quotCSE&amp;quot,
    particles: 203,
   salary:    34000,
 }
 // Calling the method
 res.show()
}توجه کنید که author از نوع struct  می باشد. ما می توانیم برای انواع Non-Struct هم متد تعریف کنیم، در مثال زیر ما  برای نوع سفارشی MyString که ساخته ایم یک متد به نام reverse برای معکوس کردن رشته مقادیر آن اضافه کردیم که به راحتی می توانیم آن را صدا بزنیم.package main

import (
	&amp;quotfmt&amp;quot
)

type MyString string

func (myStr MyString) reverse() string {
	s := string(myStr)
	runes := []rune(s)

	for i, j := 0, len(runes)-1; i &lt; j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}
	return string(runes)
}

func main() {
	myStr := MyString(&amp;quotOLLEH&amp;quot)
	fmt.Println(myStr.reverse())
}شما میتوانید متدهایی با ورودی پوینتر(Pointer) تعریف کنید:// Method with pointer receiver
func (receiver *Type) MethodName(parameterList) (returnTypes) {
 // code
}با استفاده از آرگومان از نوع اشاره گر می توانید مقادیر receiver را تغییر دهید. در حالی که در حالت قبلی(value receiver) این امکان پذیر نبود و صرفا یک کپی از receiver به متد پاس داده می شد.به طور مثال اگر بخواهیم برای نوع author مثال قبلی یک متد برای تغییر ویژگی branch آن اضافه کنیم، بدین صورت عمل می کنیم:// Method with a receiver of author type
func (a *author) changeBranch(branch string) {
      (*a).branch = branch
}برخلاف فانکشن ها، متدها می توانند هم آرگومان اشاره گر(Pointer) و هم مقدار(Value)را بپذیرند:همانطور که می دانیم در Go هنگامی که یک تابع دارای آرگومان مقدار(value) است، فقط مقادیری که به صورت value هستند را به عنوان پارامتر را می پذیرد و اگر بخواهید یک Pointer را به یک تابع Value منتقل کنید( یا برعکس)، آن را نمی پذیرد. اما یک متد Go می تواند مقادیر (Value) و اشاره گر(Pointer) را بپذیرد. همانطور که در مثال زیر نشان داده شده است:package main
import &amp;quotfmt&amp;quot

// Author structure
type author struct {
	name string
	branch string
}

// Method with a pointer receiver of author type
func (a *author) show_1(abranch string) {
	(*a).branch = abranch
}

// Method with a value  receiver of author type
func (a author) show_2() {
	a.name = &amp;quotGourav&amp;quot
	fmt.Println(&amp;quotAuthor&#039;s name(Before) : &amp;quot, a.name)
}

// Main function
func main() {
      // Initializing the values of the author structure
	res := author{
             name: &amp;quotSona&amp;quot,
            branch: &amp;quotCSE&amp;quot,
       }

       fmt.Println(&amp;quotBranch Name(Before): &amp;quot, res.branch)
       // Calling the show_1 method (pointer method) with value
       res.show_1(&amp;quotECE&amp;quot)
      fmt.Println(&amp;quotBranch Name(After): &amp;quot, res.branch)
  
       // Calling the show_2 method (value method) with a pointer
       (&amp;res).show_2()
      fmt.Println(&amp;quotAuthor&#039;s name(After): &amp;quot, res.name)
}خروجی:Branch Name(Before):  CSE
Branch Name(After):  ECE
Author&#039;s name(Before) :  Gourav
Author&#039;s name(After):  Sonaدر مثال فوق می بینید که چطور آرگومان های receiver دلخواه (از نوع value یا pointer) به متدها پاس داده می شوند.چرا از متدها به جای فانکشن ها استفاده کنیم ؟۱- متد ها به شما اجازه می دهند تا با استایل OOP در گولنگ کد بزنید، گو یک زبان برنامه نویسی شی گرا نیست و از کلاس ها پشتیبانی نمی کند. از این رو تعریف متدها بر روی typeها راهی برای دستیابی به رفتاری مشابه کلاس ها هستند. متدها به یک گروه بندی منطقی از رفتار مربوط به type شبیه کلاس ها اجازه می دهند. ۲- متد کال ها در خوانایی و درک آسان کد بهتر هستند، متدهای مختلف با نام یکسان را می توان در انواع مختلف type  تعریف کرد در حالی که توابع هم نام مجاز نیستند. یک مثال ساده فرض کنیم که ما یک ساختار(struct) مربع(Square) و دایره(Circle) داریم. می توان متدهای هم نام Area را در مربع و دایره تعریف کرد.۳- علاوه بر این متد ها باعث جلوگیری از کانفلیکت نام گذاری می شوند. چون متد به یک نوع(type) وابسته شده، شما می توانید از همان متد بر روی نوع های مختلف داشته باشید۴- متد میتونه مقدار ریسیور رو که پوینتر بهش اشاره میکنه تغییر بدهد، اینطوری از کپی کردن مقدار(value) در هر فراخوانی  خودداری میشوذ. اگر receiver یک استراکت بزرگ باشد ، این می تواند کارآمدتر(efficient) باشد.خب در این مقاله با متد ها و نحوه نوشتن آنها در گپلنگ آشنا شدیم و همینطور یادگرفتیم که متدها چه فرق هایی با فانکشن ها دارند.سخن پایانی: لطفا نظرات و انتقادات سازنده خودتون رو دریغ نکنید من حتما استقبال میکنم.</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Sun, 02 May 2021 00:17:57 +0430</pubDate>
            </item>
                    <item>
                <title>کال بک (callback) در جاوا اسکریپت</title>
                <link>https://virgool.io/JavaScript8/callbacks-in-javascript-yxlloiapeidq</link>
                <description>ابتدا نیاز می بینم که با ویژگی هایی که نوع فانکشن ها در جاوااسکریپت دارند آشنا بشویم.در جاوا اسکریپت فانکشن ها first class هستند! در واقع از نوع object هستند.  First Class به موجودیتی می گویند که می تواند داینامیک ساخته شود، به عنوان آرگومان پاس داده شود به عنوان مقدار برگشت داده شده و در نهایت حذف و نابود شوند. در یک جمله  &quot;هیچ محدودیتی در استفاده از آنها ندارید&quot;. تابع هایی که به این صورت هستند higher-order functions نامیده می شوند.  در جاوا اسکریپت: با فانکش ها مانند نوع داده های دیگر با آنها برخورد می شودفانکشن ها   از نوع object type  هستندشما می توانید فانکشن ها را در یک متغیر ذخیره کنیدفانکشن می تواند دارای property هایی باشد و همچنین link back به متد سازنده خودش!شما می توانید فانکشن ها رو به عنوان  آرگومان  به فانکش دیگر ارسال نمائیدمی توانید آنها در داخل فانکش دیگر تعریف و دستکاری کنیدشما می توانید آنها را به راحتی در داخل فانکش دیگر فراخوانی کنیدشما می توانید فانکشن ها رو به عنوان مقدار بازگشتی یک فانکش بر گردونیدهمین موارد بالا ماهیت استفاده از فانکشن های callback هستند. فانکشن callback چیست ؟فانکش callback تابعی است  که قرار است بعد از تابع دیگری اجرا شود.چرا به callback function ها نیاز داریم ؟جاوا اسکریپت یک زبان رویداد گرا است بدین معنی که ب جای صبر کردن برای دریافت پاسخ و سپس ادامه اجرا، به سراغ کد بعدی برای اجرا می رود و  در صورتی که در همین مدت به event های دیگر listen می کند. و در صورتی که پاسخ آنها آماده شده باشد دوباره به سراغ اجرای آنها خواهد رفت. در واقع کارها را به صورت asynchronous یا همان غیر همزمان انجام می دهد. برای روشن تر شدن مطلب بگذارید مثالی را بیان کنیم.function first(){
  console.log(1);
}

function second(){
  console.log(2);
}

first();
second();// 1
// 2در قطعه کد بالا همانطور که انتظار می رود فانکشfirst اول و سپس فانکشن second اجرا می شود.خب حالا اگر فانکشن first  قطعه کدی بود که سریعا اجرا و جواب را نمی داد چه ؟ مثل ارسال اطلاعات  به یک API و  دریافت جواب.برای شبیه سازی این حالت من از یکی از توابع  native جاوااسکریپت به نا setTimeOut استفاده میکنم که بعد از مدت زمان مشخصی تابع را call می کند.کد جدید ما به اینحالت می باشد:function first(){
  // Simulate a code delay
  setTimeout&#40; function(&#41;{
    console.log(1);
  }, 500 );
}

function second(){
  console.log(2);
}

first();
second();الان مهم نیست که شما نحوه کار تابع setTimeOUT را متوجه می شوید یا نه!( هر چند برای آن این لینک مفید رو معرفی می کنم)چیزی که الان مهمه این است که ما (1)console.log رو به داخل delay 500 میلی ثانیه ای خودمون انتقال دادیم.خب حالا اگر فانکشن های خودمون رو صدا  بزنیم، خروجی چه خواهد بود ؟first();
second();
// 2
// 1اگر چه ما تابع first رو ابتدا صدا زدیم ولی در نهایت خروجی آن بعد از تابع  second فراخوانی شد. این بدین معنا نیست که جاوا اسکرسپت کدهای ما رو به ترتیبی که ماخواسته بودیم اجرانکرده! بلکه جاوا اسکریپ منتظر دریافت پاسخ از تابع first نمونده و به سراغ  اجرای تابع second رفته است.شما نمی تونید فانکشن ها رو به ترتیب پس از هم صدا بزنید و انتظار داشته باشید که به همان ترتیب اجرا شوند. پس callback ها برای این هستند که مطمن شویم قطعه کد مشخصی حتما بعد از اتمام اجرای کد دیگر اجرا می شود. فانکشن های callback  برای مواردی مثل درخواست  AJAX یا  API ها که  مدت زمانی را برای ارسال  و دریافت پاسخ  طول می کشد و باید منتظر باشیم خیلی کاربرد دارد.فانکشن های callback برای این که ما مطمئن شویم تا قطعه کدی اجرا نمی شود مگر اینکه کد دیگری اجراش تمام شده باشد کاربرد دارد.بیاید callback ایجاد کنیم!function doHomework(subject) {
  alert&#40;`Starting my ${subject} homework.`&#41;;
}فانکشن doHomework ما یک موضوع رو به عنوان آرگومان میگیره و اون رو به عنوان تکلیف انجام میدهد ! مثلا:doHomework(&#039;math&#039;);
// Alerts: Starting my math homework.خب حالا callback  خودمون رو  می نویسیم، می توانیم آن را  به عنوان آرگومان  آخر  تابع doHomeWork خودمون پاس دهیم.  دقت کنید که  در این مثال هم زمان هم تعریف کرده تابع را و هم به عنوان آرگومان ارسال می کنیم.function doHomework(subject, callback) {
  alert&#40;`Starting my ${subject} homework.`&#41;;
  callback();
}

doHomework(&#039;math&#039;, function() {
  alert&#40;&#039;Finished my homework&#039;&#41;;
});بعد از اجرای قطعه کد بالا می بینیدکه شما دو alert برای شروع و پایان homework دریافت می کنید. اما اجباری نیست که فانکش callback خودمون رو حتما در تعریف تابع اصلی تعریف کرد. میتوان در جای دیگری از کد فانکشن را تعریف و سپس به صورت آرگومان به فانکش اصلی فرستاد.function doHomework(subject, callback) {
  alert&#40;`Starting my ${subject} homework.`&#41;;
  callback();
}

function alertFinished(){
  alert&#40;&#039;Finished my homework&#039;&#41;;
}

doHomework(&#039;math&#039;, alertFinished);نتیجه اجرای قطعه کد بالا همانند مثال قبلی است فقط در تعریف و صدا زدن تفاوت دارند.یک مثال دنیای واقعیمثلا هنگام استفاده از API شرکت ها و سایت های دیگر  شما به API آنها درخواست ارسال می کنید تا داده ای را بگیرید و بر اساس اون داده  ادامه بدهید، پس نیاز دارید تا آماده شدن جواب منتظر بمانید. مثلا استفاده از API وب سایت توییترT.get(&#039;search/tweets&#039;, params, function(err, data, response) {
  if(!err){
    // This is where the magic will happen
  } else {
    console.log(err);
  }
});فانکشن ()T.get برای ارسال درخواست GET به API به کار می رود.تو این درخواست ما سه تا پارامتر وجود داره. اولی &quot; search/tweets&quot; که آدرس route  ماست. Params پارامترهای ارسالی را میفرستیم باهاش و بعد از اون تابع callback مااینجا استفاده از callback خیلی مهم و کاربردیه چون ما برای ادامه کار نیاز داریم تا منتظر دریافت پاسخ از سرور بمونیم.ما نمیدونیم که درخواست ما با با موفقیت ارسال میشه یا نه، باید منتظر جواب بمونیم. وقتی که توییتر جواب میده فانکشن callback ما فراخوانی یا اصطلاحا invoke میشه. توییتر یا یک آبجت err برمیگرداند به بخاطر fail شدن درخواست یا در صورت موفقیت آمیز بودن یک آبجکت  response به عنوان جواب.فانکشن های callback  پر استفاده ترین تکنیک برنامه نویسی تابعی(functional) است. تقریبا در هرقطعه کد جاوا اسکریپت آنها رو می بینید.خب تبریک شما تقریبا با مفهوم کلی و نحوه تعریف و استفاده از callback ها آشنا شدید. </description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Sat, 23 Mar 2019 02:08:48 +0430</pubDate>
            </item>
                    <item>
                <title>با معجزه ماکروها در لاراول آشنا شوید</title>
                <link>https://virgool.io/laravel-community/macros-in-laravel-wxpq6bulzusf</link>
                <description> ابتدا به قطعه کد زیر نگاهی بندازیم که برای uppercase کردن  محتویات یک کالکشن به کار می رود:$uppercaseWords = collect([&#039;code&#039;, &#039;ferengi&#039;])-&gt;map(function($word)  {
   return strtoupper($word);
});خب این کد مشکلی نداره ولی تصور کنید که بخواهیم  تعداد زیادی کالکشن رو uppercase کنیم!  تایپ کردن و تکرار  این  قطعه کد خیلی خسته کننده خواهد شد، اینطور نیست ؟خب پس بیاید به کمک ماکروها که جزء ویژگی های جدید لاراول  هستند کدمون رو بهبود بدهیم.use Illuminate\Support\Collection;

Collection::macro(&#039;uppercase&#039;, function() {

    return collect($this-&gt;items)-&gt;map(function($word) {
        return strtoupper($word);
    });

}); حالا که ماکروی خودمون رو تعریف کردیم، پس بیاید ازش استفاده کنیم:$uppercaseWords = collect([&#039;code&#039;, &#039;daily&#039;])-&gt;uppercase();
$moreUppercaseWords = collect([&#039;code&#039;, &#039;every&#039;, &#039;day&#039;])-&gt;uppercase();
$evenMoreUppercaseWords = collect([&#039;laravel&#039;, &#039;facade&#039;])-&gt;uppercase();خب شاید شما بگویید که &quot; من می تونستم این کار رو یا  یک فانکشن ساده هم انجام بدهم&quot; حتما به این صورت:function uppercase($collection) {
...
}

$uppercaseWords = uppercase(collect([&#039;hello&#039;,&#039;Iran&#039;]));بله  می شود این  کار رو کرد ولی توجه داشته باشید که شما   با استفاده از ماکروها همچنان میتونید از فانکشن هاتون رو chain کنید و کد شما خوانایی بهتری خواهد داشت.//lots of functions
function4(function3(function2(function1(collect([&#039;Ali&#039;,&#039;Iran&#039;])))));

//lots of macros
collect([&#039;i&#039;, &#039;want&#039;, &#039;to&#039;, &#039;live&#039;, &#039;in&#039;,&#039;peace&#039;])
  -&gt;function1()
  -&gt;function2()
  -&gt;function3()
  -&gt;function4();یه مثال کاربردی تر دیگه روی کامپوننت Request لاراول بگیم، مثلا اگه بخواهیم، دامین اصلی  رکوئست رو تشخیص بدهیم  با استفاده از ماکرو ها به این صورت می تونیم:Request::macro(&#039;isTld&#039;, function ($tld) {
    return Str::is(&#039;*.&#039; . $tld, $this-&gt;root());
});

اون نامگذاری متغیر tld$ برای مخفف کلمات Top Level Domainهست، مثل com. یا net.حالا به راحتی می تونیم در رکوئست ها دامنه اصلی رو چک کنیمRequest::isTld(&#039;com&#039;) // returns true for app.com
Request::isTld(&#039;dev&#039;) // returns false for app.devیه ماکرو پیشرفته تر که  بر اساس TLD یک where به مدل اضافه میکنهBuilder::macro(&#039;whenTldMatches&#039;, function($tld, $callback) {
    if (Request::isTld($tld)) {
        call_user_func($callback-&gt;bindTo($this));
    }
    return $this;
});

SomeModel::whenTldMatches(&#039;org&#039;, function () {
    $this-&gt;where(&#039;id&#039;, &#039;&gt;&#039;, 5);
})-&gt;get();

// applies -&gt;where() on app.org but not app.comحالا شاید بپرسید کجا ماکروها رو تعریف کنم ؟‌ء Service providers ها  جای خوبی برای تعریف ماکرو ها هستند. مثلا App\Providers\AppServiceProvider ولی پیشنهاد میکنم برای ماکروها یه سرویس پرووایدر ایجاد کنید مثلا App\Providers\MacrosServiceProviderبرای کدوم کامپوننت ها می تونیم ماکرو بنویسیم ؟تقریبا برای همشون مثل  فسادهایی مانند: CacheFileLangRequestResponseRouteURLیا کلاس هایی مثل:Illuminate\Database\Eloquent\RelationIlluminate\Support\CollectionIlluminate\Routing\ResponseFactoryجالبه نه ؟ به relationship ها می تونید ماکرو اضافه کنید، مثلا :HasMany::macro(&#039;toHasOne&#039;, function() {
     return new HasOne(
     $this-&gt;getQuery,
     $this-&gt;getParent,
     $this-&gt;foreignKey,
     $this-&gt;localKey
     );
});که میاد و آخرین عنصر یک رابطه  مشخص رو میگیره.</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Tue, 12 Feb 2019 16:03:26 +0330</pubDate>
            </item>
                    <item>
                <title>الگوی طراحی Facade در لاراول</title>
                <link>https://virgool.io/laravel-community/facade-in-laravel-dadah3jemxiu</link>
                <description>ءFacade به معنی نما میباشد، دلیل استفاده از این الگوی طراحی به خاطر پنهان کردن بیشتر منطق نرم افزار و ایجاد handler هایی میباشد که کاربر میتواند با استفاده از آنها به نتیجه اولیه دست پیدا کند ، facade  به عنوان یک در بر گیرنده یا یک wrapper کار میکند، که همه محتوا را در درون خود مخفی و متدهایی را بر اساس logic مخفی شده به کاربر نشان میدهد .  class LetterProcess{

public function sendLetter(){

        $inputs = $this-&gt;request-&gt;except([&amp;quot_token&amp;quot]);

        // check if letter going out
        if ($this-&gt;isGoingOut($inputs[&amp;quotsend_type&amp;quot])) {

            if ($this-&gt;hasPermission($this-&gt;auth-&gt;id, $inputs[&amp;quotsend_type&amp;quot]))
                $this-&gt;proccessLetter($inputs);

            else
                $this-&gt;sendLetterToManagerForAccepting($inputs);

        } else {

            if( $this-&gt;sendLetterToAnotherSection($inputs[&amp;quotto_id&amp;quot]) ){

                if ($this-&gt;hasPermission($this-&gt;auth-&gt;id, $inputs[&amp;quotsend_type&amp;quot]))
                    $this-&gt;proccessLetter($inputs);
                else
                    $this-&gt;sendLetterToManagerForAccepting($inputs);
            } else
                  $this-&gt;proccessLetter($inputs);
        }
    }
}این تیکه کد بخشی از ارسال نامه اداری میباشد و به این شکل همیشه ساده نیست ولی من جهت درک بیشتر مطلب ساده نوشتمش . خوب شما فرض کنید که عملیات دیگه ایی هم باید انجام بدیم مثل ایجاد step و ایجاد notification و ارسال ایمیل و ارجاع  و کارهای دیگه ، خوب اگه بخوایم از facade استفاده کنیم . خیلی راحت میتونیم به صورت زیر عمل کنیم .  class sendLetterFacade{

    public function process(){
        $letter = new LetterProcces();
        $letter-&gt;sendLetter();
    }
} همانطور که از کد بالا میتونید ببینید، کلاس facade به عنوان یک wrapper میباشد که فقط یک متد به نام process دارد، این متد تمامی کارای که باید انجام بشه رو انجام میده، ولی در صورتی که به متدهای بیشتری جهت انجام کار نیاز داشته باشیم ، میتونیم متدهای دیگری را ایجاد کنیم ، که البته باید معنی این متد به کاری که میخواد انجام بشه نزدیک باشه و همچنین اینرو بهم باید یادمون باشه که نباید کلاس facade رو با متدهای زیادی پیچیده اش کنیم چون دلیل ایجاد کلاس پنهان کردن logic است که در کلاسهای قبلی استفاده شده است. facade کلاس در لاراوللاراول از این الگوی طراحی در فرم ورک خود استفاده کرده است. قبل از اینکه بگیم چطور می شود که یک facade کلاس در لاراول ایجاد کرد اول ببینیم که به چه شکل لاراول با facade کلاسها برخورد میکند .ما فرض میکنیم که از یک facade کلاس به نام Route در لاراول استفاده میکنیم . Route::get(&amp;quotpost&amp;quot, &amp;quotPostController@getIndex&amp;quot)-&gt;name(&amp;quotpost.index&amp;quot);خوب اگه این کلاس رو پیدا کنیم . class Route extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return &#039;router&#039;;
    }
} همانطور که از کد بالا میشه فهمید فقط یک کلاس که یدونه متد هم بیشتر نداره که اسمش هم هست getFacadeAccessor در کلاس Route وجود دارد، خوب پس کد اصلی این کلاس کجاست؟ همه متدها کجان؟ Route::get و Route::post چطوری صدا زده میشه . خوب کلاس Route از کلاس Facade ارث بری انجام میدهد، بزارید یه نگاهی به کلاس Facade بندازیم .  abstract class Facade
{

    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException(&#039;A facade root has not been set.&#039;);
        }

        return $instance-&gt;$method(...$args);
    }
} خوب در این کلاس لاراول از این magic متد جهت صدا زدن اون متد get از کلاس Route استفاده می کند. بعد از اجرا شدن این متد در اولین خط متد getFacadeRoot صدا زده می شود.  /**
     * Get the root object behind the facade.
     *
     * @return mixed
     */
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    } همانطور که از کد بالا مشخص است این متد بعد صدا زده شدن یک کار را انجام می دهد که اون هم صدا زدن متد دیگری به نام ResolveFacadeInstance میباشد. اگه به آرگومان ورودی این متد توجه کنید، از متد getFacadeAccessor استفاده شده است که این متد نام کلاس Router را بر می گرداند، چند خط بالا به آن اشاره شد . پس نام کلاس Router به متد resolveFacadeInstance ارسال میشود.  /**
     * Resolve the facade root instance from the container.
     *
     * @param  string|object  $name
     * @return mixed
     */
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        return static::$resolvedInstance[$name] = static::$app[$name];
    } خوب همانطور که از کد بالا مشخص است ، بعد از ارسال نام کلاس که Router میباشد ، چک میشود که آیا نام مورد نظر Object است یا خیر ، سپس چک می شود که آیا در خصوصیت resolvedIsntances وجود دارد یا خیر در صورت وجود نداشتن آن ، در ابتدا نام این Router را از Container بازگشایی میکند و سپس  در خصوصیت resolvedInstance ذخیره می شود .قبل از اجرای متد facade ، کلاس Application  اجرا میشود ، و عملیاتی مثل bootstrap کردن و همچنین register کردن را شروع میکند، در پوشه config/app یک آرایه به نام aliases وجود دارد که از key=&gt;value ایجاد شده است، این آرایه بعد از register شدن به ما قابلیت دسترسی به تمامی کلاسها درون خود را میدهد. بر فرض مثال ما یک کلاس به نام Route داریم که در صورت صدا زدن نام این کلاس ، این کلاس اشاره میکند به آدرس facades\route ، لاراول با استفاده از کلاس aliasLoader این نامها را register میکند. &#039;Route&#039; =&gt; Illuminate\Support\Facades\Route::class, بعد از register کردن alias ها ، سپس لاراول کلاسهای داخلی خود را ثبت می کنند ، این کلاسها در کلاس application و در متد   registerCoreContainerAliases میباشد . ما در متد getFacadeAccessor ، کلاسی به نام Router را برگرداندیم. &#039;router&#039; =&gt; [&#039;Illuminate\Routing\Router&#039;, &#039;Illuminate\Contracts\Routing\Registrar&#039;], در صورت نیاز به این کلاس لاراول خصوصیتی به نام Aliases در کلاس application  را بررسی می کند و سپس concrete کلاس را resolve  میکند . که همون Illuminate\Routing\Router . اون aliases که در فایل config/app وجود داشت را با این aliases اشتباه نگیرید، اندیس aliases که در فایل config/app وجود داشت جهت register کردن facade کلاس استفاده می شود ولی خصوصیت aliases جهت resolve کلاسهایی می باشد که لاراول آنها را در container خود ثبت کرده است . برگردیم به کلاس Facade abstract class Facade
{

    /**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException(&#039;A facade root has not been set.&#039;);
        }

        return $instance-&gt;$method(...$args);
    }
} خوب بعد از اینکه متد getFacadeRoot صدا زده شد نتیجه کد پایین به این متد برگشت داده می شود که حاوی کلاس Router میباشد.return static::$resolvedInstance[$name] = static::$app[$name]; سپس با استفاده از متغیر instance میتوان به کلاس Router و متدهای این کلاس دسترسی پیدا کرد که نتیجه را با return به محلی که Route::get صدا زده شد برگشت داده می شود.منتظر نوشته های جدید باشید ...</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Tue, 05 Feb 2019 21:41:05 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد  Helper سفارشی در لاراول</title>
                <link>https://virgool.io/laravel-community/helpers-in-laravel-fchptydyszqb</link>
                <description> همانطور که گفتم خود لاراول Helper های پیش فرض زیادی دارد که  از هسته خودش هم از آنها استفاده کرده  که بر اساس کاربردشان در دسته های مختلف گروه بندی شده اند و به احتمال زیاد شما هم از آنها در کد هایتان استفاده کرده اید. هلپر هایی مثل ()view یا ()route و یا ()assetخیلی از جاها ما نیاز داریم که یکسری کارهای رایج و متداول رو انجام بدهیم مثل: تبدبل اعداد انگلیسی به فارسی یا تبدیل تاریخ میلادی  به شمسی یا مثلا دوست داریم یک فانکشنی داشته باشیم که بدون ایجاد یا نمونه گرفتن از یک کلاس یکسری کارهای تکراری مثلا لاگ گرفتن رو برای ما انجام بده. اینطور موارد ما ما اصطلاحا یک هلپر تعریف میکنیم.ایجاد Helper سفارشی در لاراولخب حالا که  درکی نسبی از helper ها و کاربرد آنها داریم اینجا به سراغ این می رویم که چطور helper دلخواه خودمون رو بتونیم  اضافه کنیم  و از آن در همه جای اپلیکیشن استفاده کنیم. مثلا فرض کنید  که ما helper ای  میخواهیم اضافه  کنیم برای تولید یک کد رندوم برای استفاده به جای session یکتافایل جدیدی می سازیم در پوشه  app به نام  helpers.php  و فانکشن خودمون رو بدین صورت اضافه کنیم:&lt;?php

    /**
     * Generates a random unique number
     *
     * @return int
     */
   function generateSession()
 {
    return explode(&#039; &#039;,microtime())[1];
}

?&gt;خب حالا که helper خودمون ر و تعریف و ایجاد کردیم سوال این  می شود که حالا چطور باید آنها رو به اپلیکیشن خودمون اضافه کنیم و  autoload بشوند. که چندین راه برای این منظور وجود دارد.اضافه کردن فایل به قسمت files در فایل composer.jsonزمانی که تعداد کمی helper دارید و یک فایل کفایت می کند از این روش استفاده کنید.&amp;quotautoload&amp;quot: {

        &amp;quotfiles&amp;quot: [
            &amp;quotapp/helpers.php&amp;quot
        ]
} اتولود کردن کل پوشه helpers در فایل composer.jsonممکن است شما  هم helper های خودتون رو در فایل های مختلف دسته بندی کنید  مثلا ArrayHelpers.php   یا ImageHelpers.php و ...  در این صورت کل پوشه رو autoload کنید. &amp;quotautoload&amp;quot: {
        &amp;quotclassmap&amp;quot: [
            &amp;quotdatabase&amp;quot,
            &amp;quotapp/helpers&amp;quot
        ],
  }اضافه کردن service provider به لاراول و رجیستر کردن فایل helper در آن با این روش فایلهای هلپر  رو یه همراه دیگر وابستگی ها یا همون  dependancy ها رجیستر می کنید. این روش  خیلی  حرفه ای تر و قابل نگهداری تر است.به طور مثال:   app/Helpers/HelperServiceProvider.php &lt;?php
namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
 
class HelperServiceProviderextends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
 
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        require_once app_path() . &#039;/Helpers/ArrayHelpers.php&#039;;
    }
}و بعد از رجیستر کردن service provider در فایل کانفیگ app.php می تونید از آن ها به راحتی استفاده کنید.  با استفاده از یکی از دو روش ابتدایی که مشکلی برای استفاده از آنها نداریم  در نهایت  می توانیم بدین صورت از تابع  ()generateSession استفاده کنیم:generateSession();   // 1101549257123نتیجه گیریامروز با ساختار و نحوه تعریف helper  های جدید در لاراول آشنا شدیم، من مطمئن هستم به شما به عنوان توسعه دهنده حتما سراغ helper های سفارشی و جدید در لاراول خواهید رفت.  قطعا کاربرهای بیشتر و  بهتری برای تولید helper های جدید وجود دارند. خب امدوارم از مبحث امروز هم لذت برده باشید.</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Mon, 04 Feb 2019 08:51:47 +0330</pubDate>
            </item>
                    <item>
                <title>جنریتور ها در PHP</title>
                <link>https://virgool.io/@younesi/generators-in-php-gvivyn6pphj7</link>
                <description>سرعت در دنیای وب حرف اول رو میزنه، هر چه قدر که وب سایت شما سریع تر باشه کاربر پسند تره. بیشتر مواقع ما برای سریع تر کردن لود وب سایتمون به سراغ راه حل هایی مثل مینیمایز کردن  فایلهای css و js  ،  استفاده از سیستم ها و کتابخانه های Cache، کم حجم کردن تصاویر و ... می رویم. ولی یادمون می رود که به نحوه کدنویسی خومون هم توجه داشته باشیم تا شاید بهینه تر بشه کد زد. نکته های خیلی ریزی در نحوه نوشتن کدهای PHP است که رعایت کردن آنها در نهایت باعث افزایش کارایی می شوند. یکی از این موارد استفاده از generator ها است. که امروز با هم دیگه بررسی میکنیم.جتریتور (Generator) چیست ؟ جنریتورها (Generators) که از نسخه 5.5 به PHP اضافه شدند یک نوع فانکشن هستند که امکان پیاده سازیiterator  ها یا همان تکرار کننده های (مثلfor, foreach, while) بهینه رو به ما می دهند بدون اینکه حافظه زیادی رو اشغال کنند و یا باعث  پیجیده تر شدن کد شوند. چرا به Generator ها نیاز داریم ؟خب اجازه بدهید این را با یک مثال ملموس بیان کنیم.  در این مثال یک رنجی(محدوده ای) از رشته ها تولید کنیم&lt;?php

function getRange ($max = 10) {
    $array = [];

    for ($i = 1; $i &lt; $max; $i++) {
        $array[] = $i;
    }

    return $array;
}

foreach (getRange(15) as $range) {
    echo &amp;quotDataset {$range} &lt;br&gt;&amp;quot
}خب اگر اون فایل رو در لوکال هاست اجرا کنیم، خواهیم دید که خروجی شبیه زیر خواهد داشت.Dataset 1
Dataset 2
Dataset 3
Dataset 4
Dataset 5
Dataset 6
Dataset 7
Dataset 8
Dataset 9
Dataset 10
خب خروجی فوق خیلی ساده است و نیاز به توضیح خاصی نداره و کار خاص و سنگینی هم انجام نمیده ولی حالا بیایید برگردیم و یک تغییرکوچک روی کد خودمون داشته باشیم&lt;?php

foreach (getRange(PHP_INT_MAX) as $range) {
    echo &amp;quotDataset {$range} &lt;br&gt;&amp;quot
}حالا بالاترین رنج تولید شده برابر با PHP_INT_MAX  است که بزرگترین عددی است که نسخه PHP شما می تواند به آن برسد. بعد از اعمال این تغییر به صفحه مرورگر خود برگشته و صفحه مثال رو refresh کنید.این بار متواجه خواهید شد که با خطای fatal error زیر مواجه می شوید خب زیاد جالب نیست نه! PHP حافظه کم آورد! آسان ترین و راحت ترین روشی که به فکر بعضی عزیزان می رسه افزایش مقدار memory_limit در فایل php.ini است. ولی واقعا این کار غیر حرفه ای است، با این کار اجازه می دهیم که یک اسکریپت کوچک تمام حافظه ما رو اشغال کند!راه حل: استفاده از Generator ها بیاید تابع بالا رو مجدد با مقدار PHP_INT_MAX تعریف کنیم با این تفاوت که  این بار یک generator ایجاد خواهیم کرد.&lt;?php

function getRange ($max = 10) {
    for ($i = 1; $i &lt; $max; $i++) {
        yield $i;
    }
}

foreach (getRange(PHP_INT_MAX) as $range) {
    echo &amp;quotDataset {$range} &lt;br&gt;&amp;quot
}خب حالا اگر این دفعه صفحه خودتون رو رفرش کنید خواهید دید که بدون هیچ مشکلی در سرعت و کمبود حافظه کدهاتون اجرا می شوند.یک مثال ساده دیگه از جنریتورها میتونه دوباره نوشتن تابع range خود PHP باشه. این تابع دو پارامتر میگیره و باید یک آرایه از مقدار های بین آن دو رو تولید کنه و برگردونه که میتونه در نهایت منجر به ایجاد آرایه های بزرگ بشه. برای مثال صدا زدن (0,1000000)range منجر به استفاده بالای 100 مگابایت از حافظه در حال استفاده خواهد شد.به عنوان یک جایگزین بهینه تر ما تابع xrange رو پیاده سازی می کنیم. که فقط حافظه ای برای تکرار روی آبجکت و track کردن حالت جاری خواهد داشت که به نظر میرسه کمتر از 1 کیلوبایت است!&lt;?php
function xrange($start, $limit, $step = 1) {
    if ($start &lt; $limit) {

        for ($i = $start; $i &lt;= $limit; $i += $step) {
            yield $i;
        }
    } else {
        
        for ($i = $start; $i &gt;= $limit; $i += $step) {
            yield $i;
        }
    }
}
جنریتور ها چطور کار میکنند ؟جنریتورها از کلید واژه yield بجای return استفاده می کنند. Yield همانند  return است و یک مقدار رو به تابع صدا زننده  بر میگردونه ولی به جای حذف کردن فانکشن از stack ، وضعیت یا state آن را حفظ می کند.  که این به فانکشن اجازه می دهد تا از جایی که دوباره صدا زده شده ادامه پیدا کنه.جنریتور ها برای اجرای تکرارها روی مجموعه داده های بزرگ هم از لحاظ سرعت و هم  از لحاظ میزان مصرف حافظه بسیار مناسب می باشند و از آنجا که نیازی ندارید تا  کلاس Iterator رو extend کنید. برای پیاده سازی هم بسیار سریع تر می باشند.زمانهایی وجود داره که ما می خواهیم حجم بزرگی از داده رو parse کنیم مثل فایلهای log یا باید محاسبات سنگین روی نتایج بزرگ دیتابیس ما ایجاد شوند. در این صورت ما نمی خواهیم که کل حافظه رو اشغال کنیم و فضایی برای کار دیگه نداشته باشیم! دیتا حتما نباید بزرگ باشه که generator ها تاثیر خودشون رو نشون بدهند! پیشنهاد می کنم همیشه از آنها استفاده کنید. فراموش نکنید هدف ما افزایش سرعت و استفاده کم از حافظه می باشد.ء Return کردن کلیدها زمانهایی وحود داره که به مقادیر بازگشتی ما باید به صورت key-value باشند در واقع ما به key های خودمون نیاز داریم. ما می تونیم key-value ها رو بدین صورت yield کنیم.&lt;?php

function getRange ($max = 10) {
    for ($i = 1; $i &lt; $max; $i++) {
        $value = $i * mt_rand();

        yield $i =&gt; $value;
    }
}و می تونیم از آنها بدین صورت در تابع خودمون استفاده کنیم &lt;?php

foreach (getRange(PHP_INT_MAX) as $range =&gt; $value) {
    echo &amp;quotDataset {$range} has {$value} value&lt;br&gt;&amp;quot
}ارسال مقدار به generator  هاجنریتور ها مقدار هم می گیرند بدین معنی که ما میتوانیم به آنها یک مقداری را inject کنیم تا بدینوسیله به طور مثال به generator خودمون بگوییم که متوقف بشه یا خروجی رو تغییر بدهد، به طور مثال ما میخواهیم که تابع getRange  بعد از دریافت  مقدار   ‘stop’ متوقف شود.&lt;?php

function getRange ($max = 10) {
    for ($i = 1; $i &lt; $max; $i++) {
        $injected = yield $i;

        if ($injected === &#039;stop&#039;) return;
    }
} مقدار را بدین صورت به آن ارسال می کنیم:&lt;?php

$generator = getRange(PHP_INT_MAX);

foreach ($generator as $range) {
    if ($range === 10000) {
        $generator-&gt;send(&#039;stop&#039;);
    }

    echo &amp;quotDataset {$range} &lt;br&gt;&amp;quot
}حالا که با generatorها آشنا شدید امیدوارم بیشتر از آنها استفاده کنید و بهینه تر کد بنویسید. </description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Sun, 03 Feb 2019 21:48:31 +0330</pubDate>
            </item>
                    <item>
                <title>همه چیز درباره دیرکتیوهای سفارشی در Blade</title>
                <link>https://virgool.io/@younesi/%D9%87%D9%85%D9%87-%DA%86%DB%8C%D8%B2-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-%D8%AF%DB%8C%D8%B1%DA%A9%D8%AA%DB%8C%D9%88%D9%87%D8%A7%DB%8C-%D8%B3%D9%81%D8%A7%D8%B1%D8%B4%DB%8C-%D8%AF%D8%B1-blade-kocslksucwcr</link>
                <description>دیرکتیوهای  Bladeدیرکتیوها در Blade تابع هایی هستند که شرط ها و کد های پیچیده رو پنهان می کنند! Blade شامل تعدادی زیادی Directive از پیش ساخته شده است مثل دیرکتیوهای if@ یا include@ و یا  each@ که امیدوارم باهشون آشنایی داشته باشید. برای اکثر پروژه ها همین دیرکتیوهای پیش فرض می تونن کار ما رو راه بیندازن ولی وقتی پروژتون مقیاس بزرگی داره و حرفه ای تر می خواهید عمل کنید حتما به سراغ Directive ها خواهید رفت.تعریف یک Directive سفارشی در Bladeشما می توانید برای تعریف یک Directive به این صورت عمل کنید:\Blade::directive(&#039;directive_name&#039;, function ($expression) {
  return $expression;
});
پارامتر expression$ اختیاری می باشد، وقتی نیاز داریددیرکتیو شماآرگومانی را دریافت کند می توانید به عنوان آرگومان استفاده می شود.بگذارید با یک مثال ساده Hello World شروع کنم، شاید بگویید ای بابا چرا همش این مثال! ولی خب فقط محض سادگی و روانی، بعد حتما مثال پیچیده تر براتون بیان می کنم.@hello(&#039;World&#039;)اگر ما بخواهیم چنین دیرکتیوی داشته باشیم که مقداری رو بهش بدیم تا بهش سلام برسونه! به این صورت دیرکتیو خودمون رو تعریف می کنیم:namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
   /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive(&#039;hello&#039;, function ($expression) {
            return &amp;quot&lt;?php echo &#039;Hello &#039; . {$expression}; ?&gt;&quot;
        });
    }
    /**

     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
مقدار  expression$ پاس داده شده  رو به Hello متصل میکنه و در نهایت همه اینها echo   می شوند.خب! شما اولین دیرکتیو خودتون رو ساختید و می تونید در اون از کدهای خودتون استفاده کنید! ولی directive ها خیلی بیشتر از اینها میتونن کار شما رو راحت تر کنند که با یک مثال کاربردی تر برای ما عزیران شرح می دهم.مثال پنهان سازی محتوای فروشیتصور کنید شما در وب سایت خود مثلا ویدئو هایدارید که فقط دوست دارید کاربران ویژه شما که حق عضویت پرداخته اند آن ها رو تماشا کنند، مثل لاراکستشما می تونید در داخل view های خود از IF ها استفاده کنید ولی خب توجه داشته باشید که وقتی تعداد  های شما زیاد میشه چه اتفاقی میفته شما مجبورید برای هر view این کار رو انجام بدهید و logic خودتون رو اونجا تکرار کنید! حالا تصور کنید اسم یک فیلد استفاده شده درif عوض بشه، باید همه اون view ها رو ویرایش کنید!ولی با استفاده از Directive ها این کار خیلی هم راحته.فقط قبل از نوشتن دیرکتیو ها فکر کنید که چطور از اون ها استفاده خواهید کرد، برای مثال من می خواهیم چنین ساختاری در view داشته باشم .&lt;div id=&amp;quotapp&amp;quot&gt;
&lt;div class=&amp;quotpremium-video&amp;quot&gt;


    &lt;div class=&amp;quotpremium-video&amp;quot&gt;
     &lt;h2&gt;ویدئوهای کاربران مشترک&amp;&lt;h2&gt;
        @subscribed
            &lt;video src=&amp;quotvideo_for_paid_users_only.mp4&amp;quot&gt;&lt;/video&gt;
        @unsubscribed
            &lt;p&gt;برای تماشای ویدئو ها باید حق اشتراک بپردازید.&lt;/p&gt;;
        @endsubscribed
  &lt;/div&gt;
  &lt;div class=&amp;quotannoying-ads&amp;quot&gt;
       &lt;h2&gt;تبلیغات&lt;/h2&gt;
       @subscribed
       @unsubscribed
           @foreach ($annoyingAds as $ad)
           	//Ads
               {{-- Sponsorships: more than a hundred annyoing companies --}}
               &lt;div class=&amp;quotdespicable&amp;quot&gt;{!! $ad !!}&lt;/div&gt;
           @endforeach
       @endsubscribedاینجا ما از سه دیرکتیو subscribed  @unsubscribed @endsubscribed@  استفاده کردیم که حالا باید باید اون ها مطابق با نیاز های خودمون بنویسیم، دیرکتیو subscribed@بررسی می کند که آیا کاربر ما لاگین کرده و حق اشتراک دارد. دیرکتیو &lt;unsubscribed@ کار &lt;else&lt;/span&gt; رو برای دیکتیو قبلی انجام میده. در نهایت دیرکتیو endsubsribed@  هم شرط رو با یک endif می بندد.خب حالا با این تفاسیر بیایید کد دیرکتیو های خودمون رو ینویسیم.توجه داشته باشید که ما آنها را در &#x60;AppServiceProvider.php &#x60;تعریف می کنیم.&lt;?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;use Illuminate\Support\Facades\Blade;use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider{    /**     * Perform post-registration booting of services.     *     * @return void     */    public function boot()    {        Blade::directive(&#039;subscribed&#039;, function () {            $conditon = false;            // check if the user is authenticated            if (Auth::check()) {                // check if the user has a subscription                $condition = Auth::user()-&gt;isSubscribed;            }            return&lt;?php if ($condition) { ?&gt;&quot;        });        Blade::directive(&#039;unsubscribed&#039;, function () {            return &lt;?php } else { ?&gt;&quot;        });        Blade::directive(&#039;endsubscribed&#039;, function () {            return &lt;?php } ?&gt;&quot;        });    }}خب به این ترتیب شما اولین دیرکتیو سفارشی خودتون رو نوشتید. حالا با تملم لذت و راحتی از ان تو view ها استفاده کنید.مواردی که در هنگام نوشتن دیرکتیو ها باید در نظر بگیرید:هنگام گرفتن خروجی output برای جلوگیری از تزریق کد مخرب از تابع هلپر لاراول ()e استفاده کنید\Blade::directive(&#039;hello&#039;, function ($expression) {
     return &lt;?php echo &#039;Hello &#039; . e({$expression}); ?&gt;&quot;
});بعد از هر بار آپدیت کردن منطق Directive های خودتون شما نیاز دارید تا دستور زیر رو برای پاکسازی کش view ها استفاده کنید.php artisan view:clear</description>
                <category>مهدی یونسی</category>
                <author>مهدی یونسی</author>
                <pubDate>Tue, 08 Jan 2019 14:41:19 +0330</pubDate>
            </item>
            </channel>
</rss>