<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Weerasak Chongnguluam</title>
    <description>The latest articles on DEV Community by Weerasak Chongnguluam (@iporsut).</description>
    <link>https://dev.to/iporsut</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F266616%2F6bac5527-dad5-4de7-83e2-96408066555f.png</url>
      <title>DEV Community: Weerasak Chongnguluam</title>
      <link>https://dev.to/iporsut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iporsut"/>
    <language>en</language>
    <item>
      <title>ดู document ของ Bash builtin commands ผ่านคำสั่ง help</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Thu, 18 Nov 2021 14:46:04 +0000</pubDate>
      <link>https://dev.to/iporsut/duu-document-khng-bash-builtin-commands-phaankhamsang-help-559m</link>
      <guid>https://dev.to/iporsut/duu-document-khng-bash-builtin-commands-phaankhamsang-help-559m</guid>
      <description>&lt;p&gt;พวกคำสั่งที่เป็น builtin ของ Bash บางครั้งใช้ man เพื่อดู manual ไม่ได้ แต่ Bash เองเตรียมคำสั่งชื่อว่า help มาไว้เพื่อดู document ของพวก builtin commands เหล่านี้ได้&lt;/p&gt;

&lt;p&gt;ถ้าเราสั่ง help เฉยๆจะขึ้นลิสต์ command ที่สามารถดู document ได้ เช่น&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Go5KofQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5iatv38aiwkrxltlcw4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Go5KofQw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5iatv38aiwkrxltlcw4q.png" alt="help list commands" width="880" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ถ้าเราอยากดู document ของแต่ละ command ก็สั่ง help ตามด้วยชื่อ command นั้นๆเช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;help echo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5OqgrMrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ik6x0bjux9uolkaztj5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5OqgrMrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ik6x0bjux9uolkaztj5d.png" alt="help echo" width="880" height="876"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;คำสั่ง help ช่วยได้เยอะเลยยิ่งถ้าต้องเขียน shell script เพราะบางคำสั่งเราใช้ใน script บ่อยกว่าที่จะสั่งตรงๆเช่น if หรือ for&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;help for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pvwO0XtI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lqmzaqzg8zh4tf9tm6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pvwO0XtI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lqmzaqzg8zh4tf9tm6e.png" alt="help for" width="880" height="342"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;help if
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ypSvop_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxqmn1fvy948pqrxs56i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ypSvop_d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxqmn1fvy948pqrxs56i.png" alt="help if" width="880" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
    </item>
    <item>
      <title>ใช้คำสั่ง docker บน Ubuntu โดยไม่ต้องใช้ sudo</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Tue, 16 Nov 2021 00:56:26 +0000</pubDate>
      <link>https://dev.to/iporsut/aichkhamsang-docker-bn-ubuntu-odyaimtngaich-sudo-3f1h</link>
      <guid>https://dev.to/iporsut/aichkhamsang-docker-bn-ubuntu-odyaimtngaich-sudo-3f1h</guid>
      <description>&lt;p&gt;หลังจากลง Docker บน Ubuntu แล้วนั่นเราจะใช้งานมันได้เราต้องใช้สิทธิ์ root ซึ่งต้องสั่ง docker โดยใช้ sudo เช่น &lt;code&gt;sudo docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;แต่ถ้าเราอยากสั่งโดยไม่ต้องใช้ sudo ก็สามารถทำได้โดยเพิ่ม user ของเราเข้าไปใช้ usergroup ที่ชื่อว่า &lt;code&gt;docker&lt;/code&gt; ด้วยคำสั่งแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo usermod -aG docker $USER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจากนั้น logout แล้ว login อีกที (ถ้าไม่ได้ก็จัดการ restart OS อีกรอบ) เราก็สามารถสั่งคำสั่ง &lt;code&gt;docker&lt;/code&gt; ด้วย user เราเองโดยไม่ต้องใช้สิทธิ์ root ผ่าน sudo อีกแล้ว เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4b4d06n8a9t49zyrcnu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4b4d06n8a9t49zyrcnu8.png" alt="docker without sudo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;อ้างอิง: &lt;a href="https://docs.docker.com/engine/install/linux-postinstall/" rel="noopener noreferrer"&gt;https://docs.docker.com/engine/install/linux-postinstall/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>ใช้ SSH config ช่วยจำ option เวลาจะ remote ด้วย SSH</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Mon, 15 Nov 2021 15:16:30 +0000</pubDate>
      <link>https://dev.to/iporsut/aich-ssh-config-chwyccham-option-ewlaaccha-remote-dwy-ssh-3f1d</link>
      <guid>https://dev.to/iporsut/aich-ssh-config-chwyccham-option-ewlaaccha-remote-dwy-ssh-3f1d</guid>
      <description>&lt;p&gt;SSH config ช่วยให้เรา config option ของแต่ละ host เอาไว้หลายๆอันได้ ทำให้ตอนเรียก ssh ใส่แค่ชื่อ hostname ใน config ก็พอแล้ว&lt;/p&gt;

&lt;p&gt;เวลาใช้ ssh เพื่อ remote เครื่องอื่น ปกติแล้วจะสั่งประมาณนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh user@hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือถ้ามี port ที่ต่างจาก ssh ปกติ (22) ก็ใส่ option สำหรับ port เพิ่มคือ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -p 2222 user@hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือถ้ามี IdentityFile ด้วย ก็ต้องเพิ่ม option ไปอีกแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i identity.key -p 2222 user@hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างเช่นผมจะ ssh เข้า Ubuntu ที่ลงไว้ใน Virtual Box โดยใช้ vagrant ปกติแล้วจะสั่ง vagrant ssh ก็ได้ แต่ถ้าจะสั่งด้วย ssh เองโดยตรงจะต้องสั่งประมาณนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i ~/vagrants/ubuntu/.vagrant/machines/default/virtualbox/private_key -p 2222 vagrant@127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทีนี้ถ้าเราจะใช้ SSH config ช่วยเราก็สร้างไฟล์ config ที่ &lt;code&gt;$HOME/.ssh/config&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;จากนั้นกำหนดค่าแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host ubuntu-vagrant
  HostName 127.0.0.1
  IdentityFile ~/vagrants/ubuntu/.vagrant/machines/default/virtualbox/private_key
  Port 2222
  User vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ลักษณะ config file ของ SSH ก็มี key เช่น &lt;code&gt;Host&lt;/code&gt;, &lt;code&gt;HostName&lt;/code&gt;, &lt;code&gt;IdentityFile&lt;/code&gt;, &lt;code&gt;Port&lt;/code&gt; และ &lt;code&gt;User&lt;/code&gt; แล้วเว้นวรรคด้วย 1 ช่องว่าง ตามด้วยค่าที่กำหนดให้ key นั้นๆ &lt;/p&gt;

&lt;p&gt;แล้วก็มีการใช้ indentation เพื่อบอกว่าค่านั้นเป็น key/value ย่อยๆของ key หลักอีกที&lt;/p&gt;

&lt;p&gt;จากตัวอย่างผมกำหนด Host คือ &lt;code&gt;ubuntu-vagrant&lt;/code&gt; แล้วก็กำหนดค่า HostName เป็น IP หรือ Domain name ของ Host ที่เราต้องการต่อ แล้วก็ค่า IdentityFile ไปที่ path ของ private key ของ vagrant ที่กำหนดให้กับ VM ที่ต้องการ remote ตามด้วยค่า Port 2222 แล้วก็​ User คือ username ในทีนี้คือ vagrant&lt;/p&gt;

&lt;p&gt;เสร็จแล้วหลังจากนั้นเวลาเราต้องการ connect ไปที่ Ubuntu ใน VM ก็แค่สั่ง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh ubuntu-vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เท่านี้ก็ได้แล้ว&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm70t6iwshpj6klhyyrxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm70t6iwshpj6klhyyrxk.png" alt="ssh config"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cmd</category>
      <category>productivity</category>
    </item>
    <item>
      <title>หา process id ที่เปิด port อยู่ด้วย lsof -i</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Wed, 03 Nov 2021 01:50:37 +0000</pubDate>
      <link>https://dev.to/iporsut/haa-process-id-thiiepid-port-yuudwy-lsof-i-4epm</link>
      <guid>https://dev.to/iporsut/haa-process-id-thiiepid-port-yuudwy-lsof-i-4epm</guid>
      <description>&lt;p&gt;บางครั้งเรารันโปรแกรมที่เป็น background process ไว้แล้วมันเปิด port ที่เราต้องการใช้งานเอาไว้ด้วย ทำให้เราเอา port ไปให้ต่อไม่ได้ ต้องทำการปิดโปรแกรมนั้นโดยหา process id แล้วไป kill process นั้นก่อน&lt;/p&gt;

&lt;p&gt;คำสั่งที่ช่วยหาว่า process id อะไรของโปรแกรมไหนใช้ port อยู่คือ &lt;code&gt;lsof&lt;/code&gt; โดยใช้ร่วมกับ option &lt;code&gt;-i&lt;/code&gt; เช่นต้องการหาว่าโปรแกรมไหนเปิด port &lt;code&gt;12345&lt;/code&gt; อยู่ก็สั่งได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lsof -i :12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5p1aTc_X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tuv2cencey9k50hse84.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5p1aTc_X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tuv2cencey9k50hse84.jpg" alt="" width="880" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cmd</category>
    </item>
    <item>
      <title>ประกอบ slice ของ byte ด้วย bytes.Buffer</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Tue, 02 Nov 2021 01:04:50 +0000</pubDate>
      <link>https://dev.to/iporsut/prakb-slice-khng-byte-dwy-bytesbuffer-3nhf</link>
      <guid>https://dev.to/iporsut/prakb-slice-khng-byte-dwy-bytesbuffer-3nhf</guid>
      <description>&lt;p&gt;ช่วงนี้ทำงานกับ binary data บ่อยๆเพื่อทำการ encode/decode ข้อมูลที่อยู่ในรูปแบบ binary สิ่งที่เราต้องทำประจำคือเอาข้อมูลแบบ binary ที่อยู่ใน slice ของ byte ([]byte) มารวมๆกันให้เป็น byte slice ก้อนใหญ่ก้อนนึง&lt;/p&gt;

&lt;p&gt;ท่าในการเอา byte slice สองอันมารวมกันท่านึงที่นึกออกคือใช้ฟังก์ชัน &lt;code&gt;append&lt;/code&gt; เช่นมีข้อมูลแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เอา a และ b มารวมกันด้วย &lt;code&gt;append&lt;/code&gt; ได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่ว่านอกจากการใช้ &lt;code&gt;append&lt;/code&gt; แล้วเรายังใช้ type &lt;code&gt;bytes.Buffer&lt;/code&gt; ช่วยได้&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bytes.Buffer&lt;/code&gt; (&lt;a href="https://pkg.go.dev/bytes#Buffer"&gt;https://pkg.go.dev/bytes#Buffer&lt;/a&gt;) นั้นซ่อนข้อมูล &lt;code&gt;[]byte&lt;/code&gt; เอาไว้แล้วเตรียม method ที่ implements interface Reader และ Writer เอาไว้ให้ ทำให้เราประกอบข้อมูล &lt;code&gt;[]byte&lt;/code&gt; ผ่านทาง method พวกนี้ได้ และใช้ method/function อื่นๆที่ทำงานกับ Reader และ Writer ได้อีกด้วย&lt;/p&gt;

&lt;p&gt;ตัวอย่างเราสามารถประกอบ a และ b ได้โดยการใช้ bytes.Buffer ได้ดังนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;

&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างที่ซับซ้อนขึ้นเช่นถ้าเราต้องการแปลงตัวเลข 32 bits (4 bytes) เป็น binary format เช่นมีเลข 65535 แปลงเป็น 32 bits format จะได้ &lt;code&gt;00000000000000001111111111111111&lt;/code&gt; เขียนอยู่ในรูป byte slice จะได้ &lt;code&gt;[]byte{0, 0, 255, 255}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;เราจะใช้ package binary ช่วยแปลงเลขเป็น byte slice แล้ว Write เข้าไปใน buffer แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;65535&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BigEndian&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutUint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่เนื่องจากว่า bytes.Buffer นั้น implements Writer เอาไว้เราเลยเขียนแบบนี้ได้สั้นกว่า&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;65535&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BigEndian&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพราะ binary.Write ค่าแรกนั้นรับ Writer นั่นเอง&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Interface type literal</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Sun, 26 Sep 2021 05:09:00 +0000</pubDate>
      <link>https://dev.to/iporsut/interface-type-literal-1d7p</link>
      <guid>https://dev.to/iporsut/interface-type-literal-1d7p</guid>
      <description>&lt;p&gt;เวลาเราต้องการใช้ interface ส่วนใหญ่เราจะสร้าง type ชื่อใหม่สำหรับ inteface แล้วค่อยเอา type ชื่อใหม่นั้นไปใช้ ประกาศตัวแปร หรือกำหนด parameter ของ function/method แต่จริงๆเราสามารถใช้งาน interface ได้เลยโดยไม่ต้องสร้าง type ใหม่ได้เช่นกัน&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Literal
&lt;/h2&gt;

&lt;p&gt;จาก spec ของ Go &lt;a href="https://golang.org/ref/spec#Types"&gt;https://golang.org/ref/spec#Types&lt;/a&gt; บอกเอาไว้เกี่ยวกับ Type Literal เอาไว้ว่า&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A type may be denoted by a type name, if it has one, or specified using a type literal, which composes a type from existing types.&lt;/p&gt;

&lt;p&gt;TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;จากที่เห็นในลิสต์นี้ ทั้งหมดนี่คือ type ที่เราเอามาใช้งานแบบ type literal ได้ ซึ่งก็รวมถึง InterfaceType ด้วยนั่นเอง&lt;/p&gt;

&lt;h2&gt;
  
  
  ประกาศตัวแปรโดยใช้ Interface type literal
&lt;/h2&gt;

&lt;p&gt;เวลาประกาศตัวแปรของ interface type literal เราก็แค่ยก interface block แบบที่เราเคยใช้กับตอน ประกาศ type นั่นล่ะ มาใช้ได้เลย เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;finder&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เท่านี้ตัวแปร finder ก็จะเป็นตัวแปรของ type interface ที่มี 1 method คือ &lt;code&gt;Finder(keydord string) []result&lt;/code&gt; แล้ว&lt;/p&gt;

&lt;p&gt;หรือมีจุดอื่นที่เราต้องการใช้งาน interface type เช่นตอนทำ type assertion เราก็สามารถยก type literal ไปใช้ได้เช่นกันโดยไม่ต้องสร้าง type ชื่อใหม่ เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;finder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Finder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ตัวอย่างจาก standard package &lt;code&gt;errors&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;package &lt;code&gt;errors&lt;/code&gt; &lt;a href="https://pkg.go.dev/errors"&gt;https://pkg.go.dev/errors&lt;/a&gt; นั้นมี concept ใหม่คือเรื่อง &lt;code&gt;Unwrap&lt;/code&gt; error ซึ่ง document เขียนเอาไว้ว่า&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;Unwrap&lt;/code&gt;, &lt;code&gt;Is&lt;/code&gt; and &lt;code&gt;As&lt;/code&gt; functions work on errors that may wrap other errors. An error wraps another error if its type has the method &lt;code&gt;Unwrap() error&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;คือ &lt;code&gt;Unwrap&lt;/code&gt;, &lt;code&gt;Is&lt;/code&gt; และ &lt;code&gt;As&lt;/code&gt; functions ใน package errors นั้นทำงานกับ error type ที่มี method &lt;code&gt;Unwrap() error&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;บอกแบบนี้นั่นก็คือ type ที่ implements method &lt;code&gt;Unwrap() error&lt;/code&gt; นั่นละ แต่ว่าถ้าเราดู type ที่อยู่ใน document ของ &lt;code&gt;errors&lt;/code&gt; จะพบว่าเราไม่เจอ interface type สำหรับ &lt;code&gt;Unwrap() error&lt;/code&gt; method เลย&lt;/p&gt;

&lt;p&gt;แบบนี้แล้ว function &lt;code&gt;Unwrap&lt;/code&gt;, &lt;code&gt;Is&lt;/code&gt; และ &lt;code&gt;As&lt;/code&gt; มันจัดยังไงนะ ลองเข้าไปดูโค้ดของสามฟังก์ชันนี้กัน&lt;/p&gt;

&lt;p&gt;เริ่มที่ &lt;code&gt;Unwrap&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่า ใช้ type assertion แต่ว่าตรงที่อยู่ใน &lt;code&gt;()&lt;/code&gt; หลัง &lt;code&gt;err.&lt;/code&gt; นั้นไม่ใช่ชื่อ type โดยตรง แต่เป็นการใช้ interface type literal นั่นเอง&lt;/p&gt;

&lt;p&gt;ถัดไปดูที่ &lt;code&gt;Is&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;isComparable&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comparable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isComparable&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่าก็มีจุดที่ใช้ type assertion พร้อมกับใช้ interface type literal เช่นกัน แต่เป็นการเช็คว่า type implements method &lt;code&gt;Is(error) bool&lt;/code&gt; หรือเปล่า&lt;/p&gt;

&lt;p&gt;ต่อไปก็ดูที่ &lt;code&gt;As&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errors: target cannot be nil"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ptr&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNil&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errors: target must be a non-nil pointer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;targetType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;targetType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Kind&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;targetType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Implements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"errors: *target must be interface or implement error"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AssignableTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reflectlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Unwrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ก็เหมือนกับสองอันก่อนหน้านี้แต่คราวนี้คือเช็คว่า type implements method &lt;code&gt;As(interface{}) bool&lt;/code&gt; หรือเปล่า นั่นเอง&lt;/p&gt;

&lt;h2&gt;
  
  
  ทำไมเขาถึงเลือกใช้ท่านี้กันนะ 🤔
&lt;/h2&gt;

&lt;p&gt;คิดว่าอาจจะเป็นเพราะ interface ที่จะใช้งานนั้นมีแค่ method เดียว แล้วก็ไม่ได้ใช้ที่อื่นเลยยกเว้นแค่ในตัวฟังก์ชันเอง&lt;/p&gt;

&lt;p&gt;กับสิ่งที่ทำให้ทำแบบนี้ได้ก็เพราะ Go interface นั้นคน implements ไม่จำเป็นต้องรู้ type ของ interface ของแค่มี methods ตรงตาม spec แค่นั้นเอง&lt;/p&gt;

&lt;p&gt;อ้าวแล้วถ้าคน implements ไม่ได้ implement method ที่ต้องการไว้ล่ะ&lt;/p&gt;

&lt;p&gt;ก็เป็นหน้าที่ของฝั่งคนใช้ interface ในกรณีนี้คือ 3 ฟังก์ชันนี้ ต้องเขียน logic จัดการเอาไว้ว่าถ้า implement จะทำยังไง ถ้าไม่ implement จะทำยังไง ซึ่งก็ใช้ type assertion นั่นเอง&lt;/p&gt;

&lt;p&gt;อาจจะดูแปลกๆเพราะคัดกับภาษาที่คน implement ต้องระบุชัดเจนว่าจะ implement interface ไหนบ้าง เช่น (Java, C#)&lt;/p&gt;

&lt;p&gt;เพราะหลักการของ Go นั้น คนที่ต้องการใช้งาน interface ต้องเป็นคนระบุ spec เอง ในเคสนี้คือฟังก์ชัน &lt;code&gt;Unwrap&lt;/code&gt;, &lt;code&gt;Is&lt;/code&gt; และ &lt;code&gt;As&lt;/code&gt; ทั้ง 3 ฟังก์ชันนี้ใช้ Interface เพื่อให้การทำงานของตัวเองยืดหยุ่นพอที่จะทำงานกับหลายๆ type ได้ ขอแค่ type นั้น implements method ตามที่ต้องการ&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Encode / Decode Hexadecimal string to/from binary data</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Sat, 04 Sep 2021 04:50:34 +0000</pubDate>
      <link>https://dev.to/iporsut/encode-decode-hexadecimal-string-to-from-binary-data-3nc8</link>
      <guid>https://dev.to/iporsut/encode-decode-hexadecimal-string-to-from-binary-data-3nc8</guid>
      <description>&lt;p&gt;ช่วงนี้ต้องจัดการข้อมูลที่เป็น binary ซึ่งบางครั้งข้อมูลอยู่ในรูปแบบ &lt;a href="https://en.wikipedia.org/wiki/Binary-coded_decimal"&gt;BCD&lt;/a&gt; ซึ่งถ้าให้เขียนเป็นเลขฐานสองโดยตรงก็จะยาว และยากต่อการอ่านเวลา debug เกินไป ดังนั้นก็เลยแปลงให้อยู่ในเลขฐานสิบหกดีกว่าเวลาต้อง debug หรือ log ข้อมูล&lt;/p&gt;

&lt;p&gt;สำหรับ Go มี package &lt;a href="https://pkg.go.dev/encoding/hex"&gt;&lt;code&gt;encoding/hex&lt;/code&gt;&lt;/a&gt; ที่มีฟังก์ชันให้เราใช้แปลงไปมาระหว่าง binary data (&lt;code&gt;[]byte&lt;/code&gt;) ไปเป็น hexadecimal &lt;code&gt;string&lt;/code&gt; ได้ง่ายๆอยู่ คือฟังก์ชัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func EncodeToString(src []byte) string

func DecodeString(s string) ([]byte, error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างการใช้งานเช่น เมื่อเราต้องการแปลงจาก Hex ที่เป็น string กลับไปเป็น binary data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "encoding/hex"
    "fmt"
    "log"
)

func main() {
    bcdNumberHex := "1234"
    bcdNumberBytes, err := hex.DecodeString(bcdNumberHex)
    if err != nil {
        log.Fatal(err)
    }
    for _, b := range bcdNumberBytes {
        fmt.Printf("0x%x ", b)
    }
// Output:
// 0x12 0x34
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างการใช้งานเช่น เมื่อเราต้องการแปลงจาก binary data กลับไปเป็น Hex string&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "encoding/hex"
    "fmt"
)

func main() {
    bcdNumberBytes := []byte{0x12, 0x34}
    bcdNumberHex := hex.EncodeToString(bcdNumberBytes)
    fmt.Println(bcdNumberHex)

// Output:
// 1234
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
    </item>
    <item>
      <title>Go program start from main function and stop when main function exit</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Thu, 15 Jul 2021 01:07:30 +0000</pubDate>
      <link>https://dev.to/iporsut/go-program-start-from-main-function-and-stop-when-main-function-exit-2d28</link>
      <guid>https://dev.to/iporsut/go-program-start-from-main-function-and-stop-when-main-function-exit-2d28</guid>
      <description>&lt;p&gt;โปรแกรมที่เราเขียน ไม่ว่าจะเขียนด้วยภาษาอะไร มันจะมีวงจรชีวิต (life cycle) ของมันว่าจะเริ่มทำงานที่จุดไหน และ สิ้นสุดที่ตรงไหน เสมอ&lt;/p&gt;

&lt;p&gt;ถ้าเราเข้าใจ life cycle ของโปรแกรม ของภาษาที่เราใช้ หรือ เข้าใจ life cycle ของ runtime ที่เราใช้ เราก็จะไล่การทำงานของโปรแกรมได้ง่ายขึ้นเยอะเลย&lt;/p&gt;

&lt;p&gt;อย่างโปรแกรมที่เขียนด้วย Go นั้นจะเริ่มทำงานที่ฟังก์ชัน main ใน package main และจะหยุดทำงานเมื่อ main ฟังก์ชันจบการทำงาน ไม่ว่าจะด้วยการ return ปกติ, การเรียก os.Exit ฟังก์ชัน หรือโดน signal จาก OS ให้หยุดทำงาน&lt;/p&gt;

&lt;p&gt;ตัวอย่างเช่นโค้ดแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, playground"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อเรารันก็ได้ข้อความ &lt;code&gt;Hello, playground&lt;/code&gt; ในออกไปที่ standard output แต่ถ้าเราเปลี่ยนตรง &lt;code&gt;fmt.Println&lt;/code&gt; ให้ไปไปรันในอีก goroutine ล่ะ แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, playground"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เวลารันกลับไปเห็นเกิดอะไรขึ้นเลย นั่นเพราะว่า พอ main ฟังก์ชันเริ่มทำงาน มันสร้าง goroutine ใหม่ เสร็จแล้วมันก็จบการทำงานของตัวเองโดยไม่รอให้ฟังก์ชันของ goroutine อีกอันที่สร้างใหม่ได้ทำงานเลย เมื่อ main จบการทำงาน ถือว่าจบโปรแกรม goroutine ที่เหลือก็จบการทำงานด้วยไปโดยอัตโนมัติ&lt;/p&gt;

&lt;p&gt;ถ้าอยากให้ main รอให้ goroutine ที่แยกไปทำงานเสร็จก่อนก็ทำได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, playground"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้ channel ช่วย โดยให้ main รอรับค่า ส่วนใน goroutine เมื่อทำงานเสร็จก็ close channel ซะทำให้ตรงส่วนที่รอรับค่าไม่ block เลยทำให้ main จบการทำงานต่อไปได้&lt;/p&gt;

&lt;p&gt;ทีนี้ตัวอย่างถัดไป โค้ด HTTP server ง่ายๆแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่า โปรแกรมเรามันรันแล้วค้างไว้ รอรับ request มาที่ port 8000 แล้วตอบกลับไปด้วยข้อความ &lt;code&gt;Hello, World&lt;/code&gt; โดยที่จบการทำงานเมื่อเราสั่ง ctrl+c เพื่อให้ OS ส่ง signal ไปจบ process&lt;/p&gt;

&lt;p&gt;แสดงว่าโค้ดที่เราเรียก http.ListenAndServe มันเป็นฟังก์ชันที่รันนานๆเลยไม่จบจนกว่าจะมี signal มาหยุดมันนั่นเอง มันเลย block main ฟังก์ชันเอาไว้ให้ยังรันอยู่ไม่ไปไหน&lt;/p&gt;

&lt;p&gt;ถ้าเราไล่โค้ดใน &lt;code&gt;http.ListenAndServe&lt;/code&gt; เราจะไต่ไปถึงจุดที่เรียก method &lt;code&gt;(srv *Server) Serve(l net.Listener) error&lt;/code&gt; ที่มีโค้ด for loop แบบนี้อยู่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;rw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDoneChan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ErrServerClosed&lt;/span&gt;
            &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Temporary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http: Accept error: %v; retrying in %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempDelay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempDelay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;connCtx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;connCtx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;connCtx&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ConnContext returned nil"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;tempDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newConn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rwc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StateNew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runHooks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// before Serve can return&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connCtx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;มันคือ infinity loop ที่ทำงานรอรับ request แล้วส่งไปโปรเซสต่อเพื่อทำงานตาม handler ที่เรา register เอาไว้ใน main ฟังก์ชันนั่นเอง&lt;/p&gt;

&lt;p&gt;การที่เรารู้ว่าทุกอย่างเริ่มที่ main ฟังก์ชัน แต่ก็ไม่จำเป็นว่าเราต้องไล่โค้ดเริ่มที่ main ฟังก์ชันเสมอไป เพราะโค้ดใน main ฟังก์ชันจะเป็นการ initialize ค่าเริ่มต้นของสิ่งต่างๆมากกว่าเป็น business logic จริงๆแล้วเราเป็นคนออกแบบ life cycle ของโปรแกรมเราอีกทีว่า จะทำงานอะไร เมื่อมีเงื่อนไขแบบไหน เช่นถ้าเราทำ Web API เราสนใจแค่การทำงานของ endpoint หนึ่ง เราก็ไม่จำเป็นต้องเริ่มที่ main ฟังก์ชันก็ได้ แต่ขอให้เรารู้ว่าสิ่งต่างๆถูก setup เริ่มต้นมาจาก main ก่อน ก่อนที่จะเริ่ม life cycle ในการรับ request แล้ว process response นั่นเอง&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>asdf install Erlang with docs</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Wed, 09 Jun 2021 15:27:35 +0000</pubDate>
      <link>https://dev.to/iporsut/asdf-install-erlang-with-docs-38p8</link>
      <guid>https://dev.to/iporsut/asdf-install-erlang-with-docs-38p8</guid>
      <description>&lt;p&gt;&lt;a href="https://erlang.org/doc/"&gt;Erlang&lt;/a&gt; เป็นอีกภาษาที่ทีมพัฒนาเขียน document เอาไว้ดีมากๆ มีให้ทั้งเป็น manpage, html, pdf และ chunks ที่เรียกดูได้จาก erl&lt;/p&gt;

&lt;p&gt;ทีนี้ผมใช้ &lt;a href="https://github.com/asdf-vm/asdf-erlang"&gt;asdf&lt;/a&gt; เป็นเครื่องมือในการติดตั้ง Erlang ซึ่งจะไปใช้ &lt;a href="https://github.com/kerl/kerl"&gt;kerl&lt;/a&gt; อีกที แล้วถ้าอยากให้มันติดตั้ง document ให้ด้วยต้องใส่ env ให้ถูกต้อง&lt;/p&gt;

&lt;p&gt;แต่ว่าในหน้า README ของ asdf erlang plugin กับ kerl ดันบอกว่าให้ใส่แค่ env ตัวเดึยวคือตัวนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export KERL_BUILD_DOCS=yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่ลองแล้วก็ไม่เห็นจะได้ document แบบ manpage, html, pdf มาเลย แต่เจอว่าใช้งานผ่าน erl ได้&lt;/p&gt;

&lt;p&gt;สุดท้ายไล่ดูโค้ดของ asdf erlang plugin กับ kerl จนเจอว่ามันต้องระบุประเภทของ format ของ document ด้วยผ่านอีก env คือ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export KERL_DOC_TARGETS="man html pdf chunks"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ซึ่งใส่หลาย format ได้&lt;/p&gt;

&lt;p&gt;เท่านี้ก็ลง Erlang ผ่าน asdf แล้วได้ document ครบทุกประเภทแล้ว&lt;/p&gt;

</description>
      <category>erlang</category>
    </item>
    <item>
      <title>ใช้ Dev.to API ถึงข้อมูลของบทความที่เขียนออกมา</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Tue, 08 Jun 2021 02:34:35 +0000</pubDate>
      <link>https://dev.to/iporsut/dev-to-api-3p2e</link>
      <guid>https://dev.to/iporsut/dev-to-api-3p2e</guid>
      <description>&lt;p&gt;เว็บ Dev.to ที่เขียนอยู่นี้มี API ให้ใช้ด้วย ตัวอย่างเช่นถ้าเราอยากลิสต์บทความของ user คนไหนออกมาดูก็เรียก http GET ที่ endpoint นี้ แล้วใส่ query string &lt;code&gt;username&lt;/code&gt; กับกำหนดชื่อ username ที่ต้องการลิสต์บทความ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://dev.to/api/articles?username=iporsut
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfy7w6zvq727qiorefd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfy7w6zvq727qiorefd1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ซึ่งปกติจะได้ 30 บทความล่าสุด แต่ตัว API support pagination ด้วยก็ใส่ option ดึง page ต่อไปมาได้&lt;/p&gt;

&lt;p&gt;ทีนี้ถ้าอยากดูข้อมูลเฉพาะของบทความใดๆ ก็เรียก GET ไปที่ endpoint เดิม แต่ใส่ path param เป็น ID ของบทความที่ต้องการ แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://dev.to/api/articles/719722
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ซึ่งก็จะมีข้อมูลของบทความหมายเลข 719722 ออกมาซึ่งรวมทั้ง HTML ของหน้าบทความนี้ด้วย&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bcy3bd5wkqa8rjlxrad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bcy3bd5wkqa8rjlxrad.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;นอกจากนั้นยังมี API อื่นๆอีกลองเราไปดูได้ที่นี่ครับ &lt;a href="https://docs.forem.com/api/" rel="noopener noreferrer"&gt;https://docs.forem.com/api/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;มีประโยชน์มากๆเพราะเราสามารถเขียนบทความที่ dev.to แล้วไปสร้าง page ของเราเองที่ดึงข้อมูลจาก dev.to ไปแสดงเพื่อ custom การแสดงผลเองได้ด้วย&lt;/p&gt;

&lt;h2&gt;
  
  
  ขอฝาก Buy Me a Coffee
&lt;/h2&gt;

&lt;p&gt;สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/weerasak" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.buymeacoffee.com%2Fbuttons%2Fv2%2Fdefault-yellow.png" alt="Buy Me A Coffee"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devto</category>
      <category>api</category>
    </item>
    <item>
      <title>Go time Sleep with cancellable with Context</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Sun, 06 Jun 2021 15:06:11 +0000</pubDate>
      <link>https://dev.to/iporsut/go-time-sleep-with-cancellable-with-context-h3o</link>
      <guid>https://dev.to/iporsut/go-time-sleep-with-cancellable-with-context-h3o</guid>
      <description>&lt;p&gt;ฟังก์ชัน time.Sleep ใน Go เราใช้เพื่อหน่วงเวลาให้ goroutine ที่ฟังก์ชันนี้รันหยุดทำงานไปเป็นจำนวนเวลาเท่าที่เราใส่ให้ฟังก์ชันตอนเรียกใช้งาน&lt;/p&gt;

&lt;p&gt;แต่ถ้าเกิดเราต้องการให้ time.Sleep นั้นถูกยกเลิกการ Sleep ก่อนเวลาที่เราส่งให้มัน เราต้องสร้าง Sleep ฟังก์ชันขึ้นมาเองแบบที่ยกเลิกได้ &lt;/p&gt;

&lt;p&gt;สิ่งที่ช่วยได้ก็คือ type Timer ซึ่งเรากำหนดค่า duration ให้กับมันแล้วมันก็จะส่ง signal ออกมาที่ channel &lt;code&gt;C&lt;/code&gt; ซึ่งเป็น field นึงของ type Timer นั่นเอง&lt;/p&gt;

&lt;p&gt;ดังนั้น ถ้าเวลาผ่านไปยังไม่ถึง duration ที่กำหนด แล้วเราไปพยายามเอาค่าออกมาจาก &lt;code&gt;C&lt;/code&gt; มันก็จะหยุดเหมือน time.Sleep นั่นเอง&lt;/p&gt;

&lt;p&gt;โค้ดแบบนี้ ทำหน้าที่เหมือน time.Sleep&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;mySleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สิ่งที่ Timer มีมากกว่า Sleep คือมันมี method &lt;code&gt;Stop&lt;/code&gt; ให้ยกเลิก Timer ก่อนเวลาที่กำหนดได้&lt;/p&gt;

&lt;p&gt;ต่อไปเราจะทำให้ฟังก์ชัน SleepContext ของเรานั้นรับ context.Context เข้ามาด้วย เพื่อใช้เป็น signal ว่าเมื่อ context นั้นทำงานเสร็จ หรือยกเลิกแล้ว นั้นเราก็จะเรียก timer.Stop ด้วยนั่นเอง&lt;/p&gt;

&lt;p&gt;โค้ดของ SleepContext ที่จะ Sleep และยกเลิกถ้า ctx นั้นถูกยกเลิกหรือ Done เรียบร้อยแล้ว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SleepContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราใช้ select statment เพื่อรอรับค่าจากทั้ง ctx.Done() หรือ timer.C อะไรมีค่ามาก่อนก็จบการทำงานของฟังก์ชัน แต่ถ้า ctx.Done() ก่อนก็ไม่ลืมที่จะยกเลิก timer ไปด้วย เพื่อไม่ให้มันยังทำงานทำให้เกิด memory leak อยู่จนกว่าจะหมดเวลา&lt;/p&gt;

&lt;h2&gt;
  
  
  ขอฝาก Buy Me a Coffee
&lt;/h2&gt;

&lt;p&gt;สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/weerasak" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.buymeacoffee.com%2Fbuttons%2Fv2%2Fdefault-yellow.png" alt="Buy Me A Coffee"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Regular Expression for match empty string</title>
      <dc:creator>Weerasak Chongnguluam</dc:creator>
      <pubDate>Wed, 02 Jun 2021 15:05:17 +0000</pubDate>
      <link>https://dev.to/iporsut/regular-expression-for-match-empty-string-12g9</link>
      <guid>https://dev.to/iporsut/regular-expression-for-match-empty-string-12g9</guid>
      <description>&lt;p&gt;วันนี้มีโจทย์ให้ต้อง validate query string ของ API ให้รับแค่ string ที่มี A-Za-z0-9 ที่ต้องมี 3 ตัวอักษร เช่น &lt;code&gt;"ABC"&lt;/code&gt;, &lt;code&gt;"A9C"&lt;/code&gt; หรือ empty string &lt;code&gt;""&lt;/code&gt; เท่านั้น สิ่งที่ช่วยได้นั่นคือ Regular Expression นั่นเอง&lt;/p&gt;

&lt;p&gt;สำหรับ RegEx ที่ match &lt;code&gt;A-Za-z0-9&lt;/code&gt; จำนวน 3 ตัวอักษรนั้นไม่ยาก เขียนได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[A-Za-z0-9]{3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดยที่ &lt;code&gt;[]&lt;/code&gt; ใช้กำหนดว่าจะรองรับ character แบบไหนบ้าง และ &lt;code&gt;{3}&lt;/code&gt; เป็นการกำหนดจำนวนว่าต้องมีขนาด 3 ตัวอักษร&lt;/p&gt;

&lt;p&gt;สำหรับ RegEx ที่ match empty string นั้นง่ายกว่าที่คิด เพราะเขียนแค่นี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;^&lt;/code&gt; เป็นสัญลักษณ์กำหนดอักษรขึ้นต้น และ &lt;code&gt;$&lt;/code&gt; กำหนดอักษรสุดท้าย พอเอาสองตัวนี้มาติดกันแล้วไม่มีอักษรอะไรคั่น ก็ทำให้มันรองรับ empty string ได้นั่นเอง&lt;/p&gt;

&lt;p&gt;สุดท้าย เราต้องการรองรับทั้งสองแบบนี้อย่างใดอย่างหนึ่ง RegEx นั้นใช้สัญลักษณ์ &lt;code&gt;|&lt;/code&gt; แทน or เพื่อบอกว่าจะ match pattern ทางซ้ายหรือขวาก็ได้เช่นกัน กลายเป็น RegEx ที่ต้องการมีหน้าตาแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^$|[A-Za-z0-9]{3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ขอฝาก Buy Me a Coffee
&lt;/h2&gt;

&lt;p&gt;สำหรับท่านใดที่อ่านแล้วชอบโพสต์ต่างๆของผมที่นี่ ต้องการสนับสนุนค่ากาแฟเล็กๆน้อยๆ สามารถสนับสนุนผมได้ผ่านทาง Buy Me a Coffee คลิ๊กที่รูปด้านล่างนี้ได้เลยครับ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/weerasak"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rb9xKs4G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>regex</category>
    </item>
  </channel>
</rss>
