<?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: Thanabodee Charoenpiriyakij</title>
    <description>The latest articles on DEV Community by Thanabodee Charoenpiriyakij (@wingyplus).</description>
    <link>https://dev.to/wingyplus</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%2F188642%2F48cb0281-b7af-44ff-8ba9-4e50b51d8e40.png</url>
      <title>DEV Community: Thanabodee Charoenpiriyakij</title>
      <link>https://dev.to/wingyplus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wingyplus"/>
    <language>en</language>
    <item>
      <title>Functional Thinking สำหรับภาษาที่ไม่ใช่แนว Functional Programming</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Fri, 23 Dec 2022 15:15:22 +0000</pubDate>
      <link>https://dev.to/wingyplus/functional-thinking-samhrabphaasaathiiaimaichaenw-functional-programming-246j</link>
      <guid>https://dev.to/wingyplus/functional-thinking-samhrabphaasaathiiaimaichaenw-functional-programming-246j</guid>
      <description>&lt;p&gt;ที่บริษัทมี share knowledge เกี่ยวการเอาแนวคิด Functional Programming ไปใช้กับภาษาอื่นที่ไม่ใช่ Functional Programming แล้วในช่วง Q&amp;amp;A มีคนมาถามผม แต่ผมก็ตอบได้ไม่ค่อยชัดเจน เลยคิดว่ายกตัวอย่างมาใส่ใน blog ไว้น่าจะดี&lt;/p&gt;

&lt;p&gt;ปล. ผมพยายามจะอธิบายให้คนที่เขียนภาษาอื่นเข้าใจได้ด้วย ถ้าไม่เข้าใจสามารถถามหรือทักท้วงได้ครับ&lt;/p&gt;

&lt;h2&gt;
  
  
  แยกของที่เป็น side-effect ออกจาก function
&lt;/h2&gt;

&lt;p&gt;side-effect บางคนอาจจะงงว่ามันคืออะไร ลองพิจารณาโค้ดตัวอย่าง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;list_order&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;where:&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;create_date&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โค้ดตัวอย่างเป็นโค้ดที่หา order ทั้งหมดที่อยู่ในวัน ถ้าสังเกตเราจะเห็นของเป็น side-effect อยู่คือ&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Date.today()&lt;/code&gt; เปลี่ยนตามวันเวลา นั้นหมายความว่าเรียกเหมือนเดิมมันได้ผลลัพธ์ไม่เหมือนเดิม&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DB.all(...)&lt;/code&gt; เราต่อ database ถ้ามันหายตัว function อาจจะ raise exception หรือ &lt;code&gt;[]&lt;/code&gt; ก็ได้ นั้นหมายความว่าเรียกเหมือนเดิมอาจจะไม่เหมือนเดิม&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ที่นี้คงพอเห็นภาพใช่ไหมครับ ว่าจริง ๆ แล้วมันคือ function ที่เรียกไปแล้วอาจจะโดนปัจจัยภายนอกทำให้มันได้ผลลัพธ์ไม่เหมือนเดิม แล้วเราจะแก้ปัญหานี้ยังไง?​ คำตอบนึงที่ผมค้นพบคือแยก function พวกนี้ให้กลายเป็น argument ของ function นั้น ๆ เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;list_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date_fun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_all_fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date_fun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;where:&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;create_date&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;query_all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เห็นไหมครับ side-effect หายออกไปจาก function แล้วเพราะเราควบคุมปัจจัยพวกนี้ได้แล้ว เรา test function นี้ได้ด้วยการเปลี่ยนเป็น function อื่นได้ด้วย เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;list_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือถ้าอยาก integrate test ก็ทำได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;list_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คนที่เขียนภาษาแนว Imperative มักจะรู้จักกันดีในชื่อ dependency injection :)&lt;/p&gt;

&lt;h2&gt;
  
  
  เขียน function ให้เป็น function ย่อย ๆ แล้วนำมาประกอบกัน
&lt;/h2&gt;

&lt;p&gt;ในตอนเริ่มแรกผมมักจะเขียน logic ของ function ให้อยู่ในที่เดียวก่อนยกตัวอย่าง เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.07&lt;/span&gt;
  &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&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;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจากนั้นสิ่งต่อมาที่ผมทำคือแยกพวกนี้ให้เป็น function ย่อย ๆ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculate_vat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.07&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&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;calculate_net&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;calculate_vat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;calculate_net&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;total_amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;vat&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;function จะเริ่มชัดเจนว่า step การทำงานมันเป็นยังไงชัดเจน&lt;/p&gt;

&lt;p&gt;มันเริ่มกลายเป็น declarative มากกว่า imperative แล้วเห็นไหมครับ :) &lt;/p&gt;

&lt;h2&gt;
  
  
  Immutable data
&lt;/h2&gt;

&lt;p&gt;จากตัวอย่างก่อนหน้าเราจะเห็นว่าไปเปลี่ยนค่าใน &lt;code&gt;order_data&lt;/code&gt; ในบางภาษา object พวกนี้เป็นแบบ pass by reference มาความว่าเมื่อไหร่ก็ตามที่ function นี้ไป &lt;code&gt;order_data&lt;/code&gt; ที่ส่งมาจากคนเรียกจะถูกเปลี่ยนค่าตามไปด้วย นั้นหมายความว่ามันคือ function ที่เป็น side-effect นั้นเอง สิ่งที่เราควรทำคือทำให้แน่ใจว่าการแก้ไขพวกจะต้องไม่ทำให้ไปเปลี่ยน data ภายนอก หนึ่งในวิธีการคือทำการ clone object พวกให้กลายเป็น object ใหม่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;order_data_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculate_vat_to_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mf"&gt;0.07&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;order_data_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculate_net_to_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data_1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;calculate_vat_to_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# calculate vat and assign here.&lt;/span&gt;
  &lt;span class="c1"&gt;# return new order_data&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;calculate_net_to_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# calculate net and assign here.&lt;/span&gt;
  &lt;span class="c1"&gt;# return new order_data&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ปล. สำหรับภาษา Functional อาจจะไม่ต้องกังวลเพราะภาษาพวกเป็น immutable by default&lt;/p&gt;

&lt;h3&gt;
  
  
  ทำ immutable data แล้วดียังไง?
&lt;/h3&gt;

&lt;p&gt;Bug concurrency หลาย ๆ ครั้ง race condition เพราะว่ามี thread พยายาม mutate data เลยเป็นที่มาว่า Functional Programming เลยแก้เกมด้วยการ copy data ให้หมดเพืื่อลดอาการนี้&lt;/p&gt;

&lt;p&gt;เคส let's encrypt ที่เคยต้องมีการ rotate cert ทุกใบก็เพราะว่าไป mutate data ที่ไม่ควรจะ mutate สุดท้ายก็ต้อง copy data ก่อน&lt;/p&gt;

&lt;h3&gt;
  
  
  มันไม่เปลือง memory เหรอ?
&lt;/h3&gt;

&lt;p&gt;คำตอบคือเปลืองขึ้นครับ ฮาาา การทำ immutable data ดีอย่างนึงคือมีโอกาสที่ Garbage Collector จะ clear ได้เร็วขึ้นเนื่องจากมันเห็นว่าไม่มีใครใช้แล้ว หรือบางภาษาแนว ๆ Rust ก็อาจจะ clear ไปหลังจบการทำงานของ function เลย ทั้งนี้ทั้งนั้นขึ้นกับ size ของ data ที่เรา copy ไปครับ map สี่ห้า field อาจจะไม่เห็นผลอะไรครับ&lt;/p&gt;

&lt;p&gt;ผมคิดว่าน่าจะพอเห็นภาพคร่าว ๆ บ้างแล้ว หวังว่าจะเอามันไปประยุกต์ต่อได้ครับ :)&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>From UNIX command to PowerShell command</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Fri, 25 Jun 2021 15:29:53 +0000</pubDate>
      <link>https://dev.to/wingyplus/from-unix-command-to-powershell-command-25ba</link>
      <guid>https://dev.to/wingyplus/from-unix-command-to-powershell-command-25ba</guid>
      <description>&lt;p&gt;ลอง map command จาก os ตระกูล UNIX ที่ใช้ในชีวิตประจำวันมาเป็น PowerShell ของ Windows&lt;/p&gt;

&lt;h2&gt;
  
  
  mkdir
&lt;/h2&gt;

&lt;p&gt;สร้างโฟลเดอร์&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; New-Item -ItemType "directory" powershell_tut
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  cd
&lt;/h2&gt;

&lt;p&gt;เปลี่ยนโฟลเดอร์&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Set-Location powershell_tut
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  touch
&lt;/h2&gt;

&lt;p&gt;สร้างไฟล์&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ touch a.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; New-Item a.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  cp
&lt;/h2&gt;

&lt;p&gt;Copy ไฟล์จากต้นทางไปปลายทาง&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cp a.txt b.txt
$ cp -r dir_a dir_b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Copy-Item a.txt b.txt
PS&amp;gt; Copy-Item -Recurse dir_a dir_b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  rm
&lt;/h2&gt;

&lt;p&gt;ลบไฟล์หรือโฟลเดอร์&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rm a.txt
$ rm -r dir_a
$ rm -rf dir_b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Remove-Item a.txt
PS&amp;gt; Remove-Item -Recurse dir_a
PS&amp;gt; Remove-Item -Recurse -Force dir_b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  mv
&lt;/h2&gt;

&lt;p&gt;ย้ายไฟล์หรือโฟลเดอร์&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Move-Item dir_b dir_c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ls
&lt;/h2&gt;

&lt;p&gt;List ไฟล์หรือโฟลเดอร์นั้น ๆ&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Get-ChildItem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  man
&lt;/h2&gt;

&lt;p&gt;ดู manual ของโปรแกรมนั่น ๆ&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Get-Help Copy-Item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  curl
&lt;/h2&gt;

&lt;p&gt;Request data จาก url ที่ระบุ&lt;/p&gt;

&lt;p&gt;UNIX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PS&amp;gt; Invoke-RestMethod -Uri http://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>unix</category>
      <category>powershell</category>
    </item>
    <item>
      <title>"do" magic keyword option</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Mon, 30 Nov 2020 14:58:27 +0000</pubDate>
      <link>https://dev.to/wingyplus/do-magic-keyword-option-332a</link>
      <guid>https://dev.to/wingyplus/do-magic-keyword-option-332a</guid>
      <description>&lt;p&gt;สิ่งมหัศจรรย์ของ Elixir คือ เราใช้ Keyword ที่มี key ชื่อ &lt;code&gt;do&lt;/code&gt; เพื่อทำ do block ใน DSL ได้ เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;SoLazy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;defmacro&lt;/span&gt; &lt;span class="n"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nested_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kn"&gt;quote&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Print &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kn"&gt;unquote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nested_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;$ iex
Erlang/OTP 23 [erts-11.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.11.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt; require SoLazy
SoLazy
iex(2)&amp;gt; SoLazy.resources "/myapi" do
...(2)&amp;gt;   IO.puts "nested context"
...(2)&amp;gt; end
Print /myapi
nested context
:ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จบ...&lt;/p&gt;

</description>
      <category>elixir</category>
    </item>
    <item>
      <title>Rustler 101: Ferris Say</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Thu, 17 Sep 2020 15:44:21 +0000</pubDate>
      <link>https://dev.to/wingyplus/rustler-101-ferris-say-3jj6</link>
      <guid>https://dev.to/wingyplus/rustler-101-ferris-say-3jj6</guid>
      <description>&lt;p&gt;สร้าง Elixir Project ด้วย mix&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mix new ferris_ex --module FerrisEx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ใส่ &lt;code&gt;rustler&lt;/code&gt; เข้าไปใน mix dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defp deps do
  [
    {:rustler, "~&amp;gt; 0.21.1"}
  ]
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;หลังจากนั้นก็สั่ง &lt;code&gt;mix deps.get&lt;/code&gt; เพื่อ fetch dependencies&lt;/p&gt;

&lt;p&gt;ต่อมา generate rust project ผ่าน &lt;code&gt;rustler&lt;/code&gt; ก็จะมี prompt ให้ใส่ชื่อ module ลงไป ผมใส่ module ชื่อ &lt;code&gt;FerrisEx.Native&lt;/code&gt; และชื่อ rust library ก็ตามน้ำมันไป&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mix rustler.new
==&amp;gt; toml
Compiling 10 files (.ex)
Generated toml app
==&amp;gt; rustler
Compiling 5 files (.ex)
Generated rustler app
==&amp;gt; ferris_ex
This is the name of the Elixir module the NIF module will be registered to.
Module name &amp;gt; FerrisEx.Native
This is the name used for the generated Rust crate. The default is most likely fine.
Library name (ferrisex_native) &amp;gt;
* creating native/ferrisex_native/.cargo/config
* creating native/ferrisex_native/README.md
* creating native/ferrisex_native/Cargo.toml
* creating native/ferrisex_native/src/lib.rs
Ready to go! See /Users/thanabodee/src/github.com/wingyplus/ferris_ex/native/ferrisex_native/README.md for further instructions.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ต่อมาเปิด Cargo.toml ซึ่งอยู่ใน &lt;code&gt;$PWD/native/ferrisex_native/Cargo.toml&lt;/code&gt; แล้วทำการใส่ library ชื่อ &lt;code&gt;ferris_says&lt;/code&gt; ลงไป&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[dependencies]
rustler = "0.21.1"
lazy_static = "1.0"
...
ferris-says = "0.2"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;และทำการแก้โค้ดของ lib.rs ให้เป็น function ตามที่เราต้องการ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;ferris_says&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rustler&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Encoder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="p"&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;Term&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;atoms&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;rustler&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;rustler_atoms!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;atom&lt;/span&gt; &lt;span class="n"&gt;ok&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="c"&gt;// 1&lt;/span&gt;

&lt;span class="nn"&gt;rustler&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;rustler_export_nifs!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Elixir.FerrisEx.Native"&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="s"&gt;"say"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;say&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nb"&gt;None&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;// 2&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;say&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Term&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Term&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Cursor&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nn"&gt;ferris_says&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;say&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;text&lt;/span&gt;&lt;span class="nf"&gt;.into_bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nn"&gt;atoms&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;str&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_utf8&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;cursor&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จาก snippet ข้างบน&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ประกาศ atom ที่เราจะใช้ใน rust library&lt;/li&gt;
&lt;li&gt;ประกาศ function ใน module &lt;code&gt;FerrisEx.Native&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;implement function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เสร็จแล้วก็สั่ง &lt;code&gt;cargo build&lt;/code&gt; เพื่อให้ rust สร้าง dynamic library ขึ้นมา&lt;/p&gt;

&lt;p&gt;ต่อมาทำการสร้าง elixir module เพื่อ binding กับ rust library ของเรา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ./lib/ferris_ex/native.ex
defmodule FerrisEx.Native do
  use Rustler, otp_app: :ferris_ex, crate: :ferrisex_native

  def say(_text), do: :erlang.nif_error(:nif_not_loaded)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;เพื่อที่จะทำการ binding กับ rust library ของเราได้ต้องใช้ &lt;code&gt;use Rustler&lt;/code&gt; และบอกว่าจะผูกกับ crate ชื่ออะไรของเรา และต้องมี function dummy เพื่อกรณีที่ elixir binding nif ไม่ได้&lt;/p&gt;

&lt;p&gt;เสร็จแล้วก็ copy dynamic library ที่ได้จาก &lt;code&gt;cargo build&lt;/code&gt; มาไว้ที่ &lt;code&gt;priv/native&lt;/code&gt; ของ elixir&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cp ./native/ferrisex_native/target/debug/libferrisex_native.dylib ./priv/native/libferrisex_native.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;หลังจาก copy แล้วก็ทำการเปิด iex ขึ้นมาเพื่อทดสอบ binding ของเรา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(1)&amp;gt; {:ok, out} = FerrisEx.Native.say("Hello, I'm Ferris.")
{:ok,
 " ____________________\n&amp;lt; Hello, I'm Ferris. &amp;gt;\n --------------------\n        \\\n         \\\n            _~^~^~_\n        \\) /  o o  \\ (/\n          '_   -   _'\n          / '-----' \\\n"}
iex(2)&amp;gt; IO.puts(out)
 ____________________
&amp;lt; Hello, I'm Ferris. &amp;gt;
 --------------------
        \
         \
            _~^~^~_
        \) /  o o  \ (/
          '_   -   _'
          / '-----' \

:ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>elixir</category>
      <category>rust</category>
    </item>
    <item>
      <title>เรียน C# Syntax จาก Unity</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Sun, 26 Jul 2020 15:23:28 +0000</pubDate>
      <link>https://dev.to/wingyplus/c-syntax-unity-1p8</link>
      <guid>https://dev.to/wingyplus/c-syntax-unity-1p8</guid>
      <description>&lt;p&gt;ถ้าใครได้ลอง Unity จะได้เห็น type นึงที่ใช้ประจำนั่นคือ Vector2 และ Vector3 ซึ่ง blog นี้ผมจะลองทำความเข้าใจ C# จาก type ทั้งสองอันนี้กัน โดยยกตัวอย่างจาก  Vector2 เป็นหลัก&lt;/p&gt;

&lt;p&gt;ปล. หน้าตาอาจจะไม่เหมือนกันเป๊ะ แต่จุดประสงค์คือเพื่อให้อ่านโค้ดของ C# รู้เรื่อง -/-&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Struct
&lt;/h2&gt;

&lt;p&gt;Vector2 ถูกประกาศเป็น type struct เราสามารถประกาศได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Vector2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&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;y&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;ข้อดีของ struct คือมันจะ copy data ซึ่งทำให้ไม่มีผลกระทบอะไรเวลาเราส่งค่าไปให้อีก method แล้วมีการ modify เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TestFixture&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LearnStructTests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ModifyVector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vector2&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&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;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TestStruct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nf"&gt;ModifyVector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&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;ในตัวอย่าง เมื่อเราเรียก ModifyVector2 ซึ่งภายใน method นั้นมีการเปลี่ยน field &lt;code&gt;x&lt;/code&gt; ของตัวแปร &lt;code&gt;vec&lt;/code&gt; แต่ค่าของ &lt;code&gt;vec&lt;/code&gt; ภายใน &lt;code&gt;TestStruct&lt;/code&gt; กลับไม่ถูกเปลี่ยนแปลงแต่อย่างใด&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Operator Overloading
&lt;/h2&gt;

&lt;p&gt;อีก 1 feature ที่จะถูกใช้บ่อยใน Unity คือการลบ vector เพื่อเอาไปหาทิศทางที่จะเดินไป เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In Unity.&lt;/span&gt;
&lt;span class="kt"&gt;var&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;new&lt;/span&gt; &lt;span class="nf"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;34&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="p"&gt;=&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;player&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unity ใช้ feature ของ C# ที่เรียกว่า operator overloading ในการทำให้การลบ vector เหมือนลบเลข โดยเราสามารถ declare operator - ได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Vector2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&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;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="p"&gt;-(&lt;/span&gt;&lt;span class="n"&gt;Vector2&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;Vector2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;{&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;a&lt;/span&gt;&lt;span class="p"&gt;.&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;b&lt;/span&gt;&lt;span class="p"&gt;.&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;y&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;y&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;y&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;h2&gt;
  
  
  3. String formatting
&lt;/h2&gt;

&lt;p&gt;ใน type Vector2 implement interface &lt;code&gt;IFormattable&lt;/code&gt; เพื่อให้ Vector2 สามารถแปลงเป็นข้อความที่อ่านรู้เรื่องใน debug console โดยเราสามารถทำได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Vector3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFormattable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&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;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="p"&gt;-(&lt;/span&gt;&lt;span class="n"&gt;Vector2&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;Vector2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt; &lt;span class="p"&gt;{&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;a&lt;/span&gt;&lt;span class="p"&gt;.&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;b&lt;/span&gt;&lt;span class="p"&gt;.&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;y&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;y&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;y&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IFormatProvider&lt;/span&gt; &lt;span class="n"&gt;formatProvider&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="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="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"F1"&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="s"&gt;$"(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatProvider&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="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatProvider&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="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;IFormattable&lt;/code&gt; จะให้เรา implements &lt;code&gt;string ToString(string, IFormatProvider)&lt;/code&gt; เพื่อคืนค่า string ที่ format แล้วกลับไปให้ เท่านี้เราก็จะใช้ string interpolation ได้แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"(1.0, 2.0)"&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="n"&gt;vec&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สังเกตว่าผมมี check if ตรง format ไว้ใน ToString สาเหตุเพราะว่าใน C# สามารถกำหนดรูปแบบของ format ได้เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"(1.00, 2.00)"&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="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สังเกตใน string interpolation สามารถกำหนด format โดยใช้ &lt;code&gt;:&lt;/code&gt; ตามด้วย format ที่ต้องการ ผมใช้ F2 เพื่อบอกให้ format เป็นทศนิยม 2 ตำแหน่ง&lt;/p&gt;

&lt;p&gt;โค้ดเต็มดูได้ที่นี่ครับ &lt;a href="https://gist.github.com/wingyplus/08656ff8da061445f39a0af8c052e0c4/08656ff8da061445f39a0af8c052e0c4"&gt;https://gist.github.com/wingyplus/08656ff8da061445f39a0af8c052e0c4/08656ff8da061445f39a0af8c052e0c4&lt;/a&gt;&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Validate signature สำหรับ LINE webhook</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Thu, 02 Apr 2020 16:05:26 +0000</pubDate>
      <link>https://dev.to/wingyplus/validate-signature-line-webhook-2i01</link>
      <guid>https://dev.to/wingyplus/validate-signature-line-webhook-2i01</guid>
      <description>&lt;p&gt;LINE webhook api มีสิ่งขั้นตอนนึงที่ต้องทำคือการ validate signature เพื่อยืนยันว่า request ที่เข้ามานั้นมาจาก Official Account ของเราจริงๆ ซึ่งถ้าใช้ภาษาที่ official LINE support แล้วละก็จะมีจะ function ให้ใช้งานอย่าง line-bot-sdk-go ที่มี &lt;a href="https://github.com/line/line-bot-sdk-go/blob/master/linebot/webhook.go#L32"&gt;ParseRequest(*http.Request)&lt;/a&gt; ให้ใช้งานก็จะ validate signature จาก request header ให้อัตโนมัติ&lt;/p&gt;

&lt;p&gt;ถ้าลองลอกการทำงานของ validate signature เพื่อนำมาทำ webhook ใน​​ Elixir น่าจะได้ประมาณนี้&lt;/p&gt;

&lt;p&gt;ขั้นตอนแรกสร้าง hash ด้วย HMAC-SHA256 โดยใช้ key เป็น ​channel secret และ data เป็น request body ที่ LINE ส่งเข้ามา function จะได้หน้าตาประมาณนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defp sign_signature(channel_secret, body) do
  :crypto.hmac(:sha256, channel_secret, body)
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จากนั้น encode ด้วย base64 จะได้ signature ที่ LINE ส่งมาทาง request header ซึ่งใช้ pipe operator pipe ตัว hash ที่เราสร้างเข้าไป Base.encode เลยจะง่ายกว่า&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defp sign_signature(channel_secret, body) do
  :crypto.hmac(:sha256, channel_secret, body) |&amp;gt; Base.encode64()
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จากนั้นเอา signature ที่ได้ไป compare กับ signature จาก request header&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def validate(signature, body, channel_secret) do
  validate(signature, sign_signature(channel_secret, body))
end

defp validate(signature, signature), do: :ok
defp validate(_, _), do: :invalid_signature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ผมสร้าง validate/3 เพื่อรับ signature จาก request header แล้วส่งเข้าไปที่ validate/2 เพื่อใช้ pattern matching ดูว่าเป็น signature เดียวกันก็จะตอบ &lt;code&gt;:ok&lt;/code&gt; ไปเลยส่วน case อื่นก็ถือว่า &lt;code&gt;:invalid_signature&lt;/code&gt; ไป &lt;/p&gt;

&lt;p&gt;ปล. จริงๆ จะใช้ &lt;code&gt;case &amp;lt;&amp;gt; do ... end&lt;/code&gt; ก็ได้ไม่ว่ากัน เพราะความตั้งใจผมคือต้องการแยกเคสให้อ่านง่าย&lt;/p&gt;

&lt;p&gt;ผมลองสร้างตัวอย่างโดย port มาจาก echo_bot ที่อยู่ใน line-bot-sdk-go &lt;a href="https://github.com/wingyplus/echo_bot/"&gt;ที่นี่&lt;/a&gt;ลองดูหรือ discuss กันได้ครับ :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ข้อควรระวัง&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LINE จะ sign signature โดยรวม space ใน request body กรณีนี้จะเจอตอนที่ LINE ส่ง body แบบ indent JSON มาให้​ซึ่งหากเราใช้ Plug.Parsers แล้วมาดูจาก conn.body_params  อาจจะผิดได้ (เคสนี้ผมเจอตอน verify webhook หาอยู่พักนึงถึงเข้าใจ)&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>line</category>
    </item>
    <item>
      <title>Vue 101 จาก Elm</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Tue, 17 Mar 2020 12:43:49 +0000</pubDate>
      <link>https://dev.to/wingyplus/vue-101-elm-42f9</link>
      <guid>https://dev.to/wingyplus/vue-101-elm-42f9</guid>
      <description>&lt;p&gt;หากจะทำแบบนี้ใน Vue โดยเทียบกับ Elm จากตัวอย่าง counter app &lt;a href="https://ellie-app.com/8kChZLnNmfta1"&gt;https://ellie-app.com/8kChZLnNmfta1&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Elm mount app โดยใช้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var app = Elm.Main.init({ node: document.querySelector('main') })
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Vue ก็ทำโดยสร้าง Vue instance โดย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new Vue({ render: h =&amp;gt; h(App) }).$mount('#app')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;view ใน Elm เป็น function ที่รับ data (หรือเรียกว่า Model)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;view model =
    div []
        [ button
            [ onClick Increment ]
            [ text "+" ]
        , p
            []
            [ text &amp;lt;| String.fromInt model ]
        , button
            [ onClick Decrement ]
            [ text "-" ]
        ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ใช้ Vue แบบ single file component จะใช้ tag template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;button @click="increment()"&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;p&amp;gt;{{ count }}&amp;lt;/p&amp;gt;
    &amp;lt;button @click="decrement()"&amp;gt;-&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Elm ต้อง initialize data ผ่าน &lt;code&gt;init&lt;/code&gt; และ manage logic ด้วย update function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init =
    0


update msg model =
    case msg of
        Increment -&amp;gt;
            model + 1

        Decrement -&amp;gt;
            model - 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ส่วน Vue ก็คล้ายกันโดยมี &lt;code&gt;data&lt;/code&gt; และ &lt;code&gt;methods&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
export default {
  data: () =&amp;gt; ({
    count: 0
  }),
  methods: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;แต่สิ่งที่มันต่างกับ Elm คือ update ของ Elm ใช้ update view ทั้ง application ส่วน Vue update เพียงแค่ใน component ถ้าอยากจะให้ update ทั้ง component ต้องใช้ &lt;code&gt;vuex&lt;/code&gt; ช่วยโดยแยก data และการ update ออกมาจาก component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count += 1
    },
    decrement(state) {
      state.count -= 1
    }
  }
})

new Vue({
  store,
  render: h =&amp;gt; h(App),
}).$mount('#app')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จากนั้นใช้วิธีการ commit mutation เข้าไปจากใน component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
export default {
  name: "App",
  computed: {
    count() {
      return this.$store.state.count;
    }
  },
  methods: {
    increment() {
      this.$store.commit("increment");
    },
    decrement() {
      this.$store.commit("decrement");
    }
  }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ลองเทียบ state จาก state debugger&lt;/p&gt;

&lt;p&gt;ของ Elm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--THVP1X9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f6gkj5y10me8sho75g3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--THVP1X9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f6gkj5y10me8sho75g3a.png" alt="Elm Debugger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ของ Vuex&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j2BUzi0k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2s2ky1drxx1kh8xqobpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j2BUzi0k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2s2ky1drxx1kh8xqobpu.png" alt="Vuex Debugger"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elm</category>
      <category>vue</category>
    </item>
    <item>
      <title>ใช้งาน Jaeger trace ร่วมกับ OpenTelemetry</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Mon, 10 Feb 2020 06:41:20 +0000</pubDate>
      <link>https://dev.to/wingyplus/jaeger-trace-opentelemetry-3b15</link>
      <guid>https://dev.to/wingyplus/jaeger-trace-opentelemetry-3b15</guid>
      <description>&lt;p&gt;จาก&lt;a href="https://dev.to/wingyplus/tracing-opentelemetry-go-262e"&gt;บทความ&lt;/a&gt; ที่แล้วเราใช้ exporter เป็นแบบ &lt;code&gt;stdout&lt;/code&gt; เพื่อส่ง traces ออกไปที่ stdout ของ os คราวนี้เราจะมาใช้งานร่วมกับ Jaeger กัน&lt;/p&gt;

&lt;p&gt;ในบทความนี้ผมใช้ jaeger แบบ all-in-one เพื่อให้ง่ายต่อการ setup และทดสอบโดยสามารถได้ด้วย docker แบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; jaeger &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;COLLECTOR_ZIPKIN_HTTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9411 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5775:5775/udp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 6831:6831/udp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 6832:6832/udp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5778:5778 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 16686:16686 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 14268:14268 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 9411:9411 &lt;span class="se"&gt;\&lt;/span&gt;
  jaegertracing/all-in-one:1.8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จากนั้นเราจะเปลี่ยน exporter จาก stdout เป็น jaeger โดยใช้ package &lt;code&gt;go.opentelemetry.io/otel/exporter/trace/jaeger&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go get &lt;span class="nt"&gt;-v&lt;/span&gt; go.opentelemetry.io/otel/exporter/trace/jaeger@v0.2.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
    &lt;span class="s"&gt;"go.opentelemetry.io/otel/exporter/trace/jaeger"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// in initTrace().&lt;/span&gt;
&lt;span class="n"&gt;exporter&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;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCollectorEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:14268/api/traces"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ServiceName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"github.com/wingyplus/basic"&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="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="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"have some problems while creating jaeger exporter: %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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จากนั้นทำการรันด้วย &lt;code&gt;go run&lt;/code&gt; และเปิด Jaeger UI มาดูผ่าน &lt;code&gt;http://localhost:16686&lt;/code&gt; จะเห็นแบบรูปด้านล่าง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MguL7rPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ml30x967ulc8lquqp481.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MguL7rPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ml30x967ulc8lquqp481.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oUG0Wbyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ukg0qeeum53vx4y0aw80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oUG0Wbyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ukg0qeeum53vx4y0aw80.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>go</category>
    </item>
    <item>
      <title>มาเริ่มต้นใช้งาน tracing กับ OpenTelemetry ด้วย Go</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Sun, 09 Feb 2020 12:19:51 +0000</pubDate>
      <link>https://dev.to/wingyplus/tracing-opentelemetry-go-262e</link>
      <guid>https://dev.to/wingyplus/tracing-opentelemetry-go-262e</guid>
      <description>&lt;p&gt;OpenTelemetry เป็นโครงการเพื่อช่วยจัดการเรื่อง tracing กับ metrics และทำให้ application ไม่เกิด vendor lock-in กับระบบ tracing หรือ metrics เจ้าใดเจ้านึง ซึ่งโครงการนี้ต่อยอดมาจาก OpenTracing กับ OpenCensus และทำตามมาตรฐาน &lt;a href="https://www.w3.org/TR/trace-context/"&gt;W3 Tracing Context&lt;/a&gt; (ผมยังไม่ได้อ่านรายละเอียดของ Tracing Context มากเท่าไหร่ เดี๋ยวว่างๆ ค่อยมาสรุปอีกที) &lt;/p&gt;

&lt;p&gt;เจ้าตัว OpenTelemetry เองก็ support programming language หลายภาษาอยู่เหมือน เช่น Go, Java, Python, Erlang, Rust เป็นต้น โดยในบล็อคนี้จะเน้น Go และการทำ tracing เป็นหลัก (ภาษาอื่นเขียนไม่เป็น 555)&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นแรกสร้าง module
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir otel-todo
$ cd otel-todo &amp;amp;&amp;amp; go mod init github.com/wingyplus/otel-todo
go: creating new go.mod: module github.com/wingyplus/otel-todo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  ทำการ initialize tracing
&lt;/h2&gt;

&lt;p&gt;ในการ initialize tracing นั้นจะมีสามขั้นตอน ขั้นแรกคือสร้าง exporter เพื่อบอก OpenTelemetry ว่าจะ export trace ไปที่ระบบไหน ซึ่งตอนนี้ &lt;code&gt;opentelemetry-go&lt;/code&gt; ซัพพอร์ตแค่สามระบบ &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;stdout ง่ายๆ คือ print ออก stdout ในรูปแบบ json format &lt;/li&gt;
&lt;li&gt;jaeger เป็นระบบ distributed tracing ของ Uber&lt;/li&gt;
&lt;li&gt;stackdriver ของ Google Cloud&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตอนนี้เราจะเริ่มง่ายๆ ด้วยการใช้ stdout ก่อน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&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;"log"&lt;/span&gt;

    &lt;span class="s"&gt;"go.opentelemetry.io/otel/exporter/trace/stdout"&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;initTrace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;exporter&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;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PrettyPrint&lt;/span&gt;&lt;span class="o"&gt;:&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="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"have some errors while creating stdout exporter: %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="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ต่อมาทำการสร้าง provider เพื่อบอกความถี่ในการ sync trace ไปหา exporter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
    &lt;span class="n"&gt;sdktrace&lt;/span&gt; &lt;span class="s"&gt;"go.opentelemetry.io/otel/sdk/trace"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c"&gt;// in initTrace().&lt;/span&gt;
&lt;span class="n"&gt;provider&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;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DefaultSampler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AlwaysSample&lt;/span&gt;&lt;span class="p"&gt;()}),&lt;/span&gt;
    &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSyncer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&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;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="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"have some problems while creating provider: %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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ในตัวอย่างข้างบนนั้นผมใส่เป็น &lt;code&gt;AlwaysSample()&lt;/code&gt; เพื่อเอาทุก trace ที่เกิดขึ้นในระบบ&lt;/p&gt;

&lt;p&gt;ขั้นตอนสุดท้ายทำการ set provider เข้าไปที่ package global&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
    &lt;span class="s"&gt;"go.opentelemetry.io/otel/api/global"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// in initTrace().&lt;/span&gt;
&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetTraceProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  ใช้งาน tracing
&lt;/h2&gt;

&lt;p&gt;ขั้นแรกทำการดึง provider ออกมาจาก global&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;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;initTrace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"github.com/wingyplus/basic"&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;จากนั้นทำการสร้าง span ด้วย &lt;code&gt;tracer.WithSpan&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// in main().&lt;/span&gt;
&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSpan&lt;/span&gt;&lt;span class="p"&gt;(&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;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"foo"&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;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="kt"&gt;error&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ลองทดสอบการทำงานด้วย &lt;code&gt;go run&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"SpanContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"TraceID"&lt;/span&gt;: &lt;span class="s2"&gt;"5883cc5d9604907026cf1cc8f651206a"&lt;/span&gt;,
                &lt;span class="s2"&gt;"SpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"73ebe6c408d24147"&lt;/span&gt;,
                &lt;span class="s2"&gt;"TraceFlags"&lt;/span&gt;: 1
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"ParentSpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"0000000000000000"&lt;/span&gt;,
        &lt;span class="s2"&gt;"SpanKind"&lt;/span&gt;: 1,
        &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"github.com/wingyplus/basic/foo"&lt;/span&gt;,
        &lt;span class="s2"&gt;"StartTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:10:49.844055+07:00"&lt;/span&gt;,
        &lt;span class="s2"&gt;"EndTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:10:49.844060721+07:00"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Attributes"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"MessageEvents"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"Links"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"Status"&lt;/span&gt;: 0,
        &lt;span class="s2"&gt;"HasRemoteParent"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
        &lt;span class="s2"&gt;"DroppedAttributeCount"&lt;/span&gt;: 0,
        &lt;span class="s2"&gt;"DroppedMessageEventCount"&lt;/span&gt;: 0,
        &lt;span class="s2"&gt;"DroppedLinkCount"&lt;/span&gt;: 0,
        &lt;span class="s2"&gt;"ChildSpanCount"&lt;/span&gt;: 0
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;เราสามารถสร้าง span ภายใน &lt;code&gt;WithSpan&lt;/code&gt; ได้อีกโดยใช้ context ของ &lt;code&gt;WithSpan&lt;/code&gt; ที่เป็นตัว root เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSpan&lt;/span&gt;&lt;span class="p"&gt;(&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;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"foo"&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;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="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bar"&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;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="kt"&gt;error&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ถ้าลองรันดู จะเห็นว่าจะมีสอง span เกิดขึ้นมา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"SpanContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"TraceID"&lt;/span&gt;: &lt;span class="s2"&gt;"58e32b2438efda4d90db7b0ce0db9371"&lt;/span&gt;,
        &lt;span class="s2"&gt;"SpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"040c29233e95fca5"&lt;/span&gt;,
        &lt;span class="s2"&gt;"TraceFlags"&lt;/span&gt;: 1
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"ParentSpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"8fc213b9e9b84a98"&lt;/span&gt;,
    &lt;span class="s2"&gt;"SpanKind"&lt;/span&gt;: 1,
    &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"github.com/wingyplus/basic/bar"&lt;/span&gt;,
    &lt;span class="s2"&gt;"StartTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:13:36.753668+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"EndTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:13:36.75367142+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Attributes"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"MessageEvents"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Links"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Status"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"HasRemoteParent"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"DroppedAttributeCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedMessageEventCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedLinkCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"ChildSpanCount"&lt;/span&gt;: 0
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"SpanContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"TraceID"&lt;/span&gt;: &lt;span class="s2"&gt;"58e32b2438efda4d90db7b0ce0db9371"&lt;/span&gt;,
        &lt;span class="s2"&gt;"SpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"8fc213b9e9b84a98"&lt;/span&gt;,
        &lt;span class="s2"&gt;"TraceFlags"&lt;/span&gt;: 1
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"ParentSpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"0000000000000000"&lt;/span&gt;,
    &lt;span class="s2"&gt;"SpanKind"&lt;/span&gt;: 1,
    &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"github.com/wingyplus/basic/foo"&lt;/span&gt;,
    &lt;span class="s2"&gt;"StartTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:13:36.753663+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"EndTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:13:36.754156451+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Attributes"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"MessageEvents"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Links"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Status"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"HasRemoteParent"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"DroppedAttributeCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedMessageEventCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedLinkCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"ChildSpanCount"&lt;/span&gt;: 1
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จะสังเกตเห็นว่า span ที่มีชื่อว่า &lt;code&gt;"github.com/wingyplus/basic/bar"&lt;/code&gt; จะมี parent เป็น &lt;code&gt;"8fc213b9e9b84a98"&lt;/code&gt; ซึ่งเป็น span id ที่อยู่ใน &lt;code&gt;SpanContext&lt;/code&gt; ของ span ที่ชื่อ &lt;code&gt;"github.com/wingyplus/basic/foo"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ที่นี่ลองหน่วงการทำงานของ span ดู&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// in main().&lt;/span&gt;
&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSpan&lt;/span&gt;&lt;span class="p"&gt;(&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;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"foo"&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;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="kt"&gt;error&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="m"&gt;3&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;tracer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"bar"&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;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="kt"&gt;error&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="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;Second&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"SpanContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"TraceID"&lt;/span&gt;: &lt;span class="s2"&gt;"cbbff287daac4270963300393e1122f4"&lt;/span&gt;,
        &lt;span class="s2"&gt;"SpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"6a7e00be07802205"&lt;/span&gt;,
        &lt;span class="s2"&gt;"TraceFlags"&lt;/span&gt;: 1
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"ParentSpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"a7afe9f612e34427"&lt;/span&gt;,
    &lt;span class="s2"&gt;"SpanKind"&lt;/span&gt;: 1,
    &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"github.com/wingyplus/basic/bar"&lt;/span&gt;,
    &lt;span class="s2"&gt;"StartTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:16:30.103175+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"EndTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:16:35.106123127+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Attributes"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"MessageEvents"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Links"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Status"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"HasRemoteParent"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"DroppedAttributeCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedMessageEventCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedLinkCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"ChildSpanCount"&lt;/span&gt;: 0
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"SpanContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"TraceID"&lt;/span&gt;: &lt;span class="s2"&gt;"cbbff287daac4270963300393e1122f4"&lt;/span&gt;,
        &lt;span class="s2"&gt;"SpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"a7afe9f612e34427"&lt;/span&gt;,
        &lt;span class="s2"&gt;"TraceFlags"&lt;/span&gt;: 1
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"ParentSpanID"&lt;/span&gt;: &lt;span class="s2"&gt;"0000000000000000"&lt;/span&gt;,
    &lt;span class="s2"&gt;"SpanKind"&lt;/span&gt;: 1,
    &lt;span class="s2"&gt;"Name"&lt;/span&gt;: &lt;span class="s2"&gt;"github.com/wingyplus/basic/foo"&lt;/span&gt;,
    &lt;span class="s2"&gt;"StartTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:16:27.102542+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"EndTime"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-02-09T19:16:35.107031106+07:00"&lt;/span&gt;,
    &lt;span class="s2"&gt;"Attributes"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"MessageEvents"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Links"&lt;/span&gt;: null,
    &lt;span class="s2"&gt;"Status"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"HasRemoteParent"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"DroppedAttributeCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedMessageEventCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"DroppedLinkCount"&lt;/span&gt;: 0,
    &lt;span class="s2"&gt;"ChildSpanCount"&lt;/span&gt;: 1
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จะเห็นว่า span &lt;code&gt;"github.com/wingyplus/basic/foo"&lt;/code&gt; จะมี start time กับ end time ห่างกันประมาณ 8 วินาที เพราะ span &lt;code&gt;"github.com/wingyplus/basic/bar"&lt;/code&gt; ใช้เวลา 5 วินาทีนั่นเอง&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>go</category>
    </item>
    <item>
      <title>หัด Erlang and Elixir v0.3.0 - atom</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Wed, 08 Jan 2020 14:26:17 +0000</pubDate>
      <link>https://dev.to/wingyplus/erlang-and-elixir-v0-3-0-atom-1e6p</link>
      <guid>https://dev.to/wingyplus/erlang-and-elixir-v0-3-0-atom-1e6p</guid>
      <description>&lt;p&gt;atom ใน Erlang ขึ้นด้วยด้วยอักษรตัวเล็ก หรือใช้ &lt;code&gt;'&lt;/code&gt; ครอบ text เอา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;centimeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;centimeter&lt;/span&gt;
&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'Centimeter'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;'Centimeter'&lt;/span&gt;
&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;'Centi meter'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;'Centi meter'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ส่วนของ Elixir ใช้ &lt;code&gt;:&lt;/code&gt; นำหน้าหรือขึ้นต้นด้วยตัวอักษรตัวใหญ่ ถ้าอยากจะใช้ &lt;code&gt;'&lt;/code&gt; แบบ Erlang ให้เติม &lt;code&gt;:&lt;/code&gt; เข้าไป&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:centimeter&lt;/span&gt;
&lt;span class="ss"&gt;:centimeter&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;'Centimeter'&lt;/span&gt;
&lt;span class="ss"&gt;:Centimeter&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;'Centi meter'&lt;/span&gt;
&lt;span class="ss"&gt;:"Centi meter"&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;This_is_greeting&lt;/span&gt;
&lt;span class="no"&gt;This_is_greeting&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ทั้งสองภาษามี function &lt;code&gt;is_atom&lt;/code&gt; เพื่อเอาไว้ตรวจสอบว่า value นั้นเป็น atom หรือไม่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;centimeter&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'Centimeter'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;'Centi meter'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:centimeter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(:&lt;/span&gt;&lt;span class="s1"&gt;'Centimeter'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(:&lt;/span&gt;&lt;span class="s1"&gt;'Centi meter'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;This_is_greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;boolean ของทั้งสองภาษาก็เป็น atom เช่นเดียวกัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;NOTE: ที่เราเห็น true/false ใน Elixir ใน atom นั้นสาเหตุเพราะ compiler จะแปลง true/false ให้กลายเป็น &lt;code&gt;:true&lt;/code&gt; กับ &lt;code&gt;:false&lt;/code&gt; ที่เราใช้ตัวอักษรตัวใหญ่เคสนั้นก็น่าจะทำนองเดียวกัน&lt;/p&gt;

&lt;p&gt;Module ใน Elixir และ Erlang เองก็เป็น atom เหมือนกันนะ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt; &lt;span class="c"&gt;%% module lists
&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;## module List&lt;/span&gt;
&lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;NOTE: ในเคสของ Elixir จะแปลงไปเป็น &lt;code&gt;:'Elixir.List&lt;/code&gt; ให้เองโดย compiler&lt;/p&gt;

</description>
      <category>erlang</category>
      <category>elixir</category>
    </item>
    <item>
      <title>หัด Erlang and Elixir v0.2.0 - variable</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Wed, 08 Jan 2020 14:03:23 +0000</pubDate>
      <link>https://dev.to/wingyplus/erlang-and-elixir-v0-2-0-variable-2gjh</link>
      <guid>https://dev.to/wingyplus/erlang-and-elixir-v0-2-0-variable-2gjh</guid>
      <description>&lt;p&gt;การสร้างตัวแปรใน Erlang นั้นจะใช้ชื่อตัวแปรขึ้นต้นด้วยตัวอักษรตัวใหญ่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="s"&gt;"hello"&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="s"&gt;"hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ใน Erlang นั้นจำเป็นต้องใช้ &lt;code&gt;.&lt;/code&gt; เป็นตัว end statement เสมอ และ assign ให้ตัวแปรเดิมทับไม่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"new hello"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="n"&gt;hand&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="s"&gt;"new hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;NOTE: ใน Erlang shell เราสามารถทำยกเลิก variable binding ได้ด้วยการใช้ function f() เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"new hello"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="s"&gt;"new hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ส่วนของ Elixir นั้นใช้ขึ้นด้วยตัวเล็ก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;
&lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;แถมต่างกับ Erlang ตรง assign ทับได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"new hello"&lt;/span&gt;
&lt;span class="s2"&gt;"new hello"&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;
&lt;span class="s2"&gt;"new hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;แต่ถ้าอยากไม่ให้ re-assign ค่าใหม่ที่ไม่ใช่ค่าเดิมได้ จะต้องใช้ &lt;code&gt;^&lt;/code&gt; นำหน้าตัวแปร Elixir จะทำการ match value ระหว่างสองข้างให้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;MatchError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="n"&gt;hand&lt;/span&gt; &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="ss"&gt;value:&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;erl:&lt;/span&gt;&lt;span class="mi"&gt;453&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_eval&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;237&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_eval&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;loop&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;ex:&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;IEx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"new hello"&lt;/span&gt; &lt;span class="c1"&gt;# สามารถ assign ได้เพราะค่าทางด้านขวาเป็นค่าเดียวกับด้านซ้าย&lt;/span&gt;
&lt;span class="s2"&gt;"new hello"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>erlang</category>
      <category>elixir</category>
    </item>
    <item>
      <title>หัด Erlang and Elixir v0.1.0</title>
      <dc:creator>Thanabodee Charoenpiriyakij</dc:creator>
      <pubDate>Mon, 06 Jan 2020 16:18:59 +0000</pubDate>
      <link>https://dev.to/wingyplus/erlang-and-elixir-v0-1-0-53o8</link>
      <guid>https://dev.to/wingyplus/erlang-and-elixir-v0-1-0-53o8</guid>
      <description>&lt;p&gt;หลังจากไปงาน Elixir meetup ครั้งที่ผ่านมา สารภาพว่าไปไม่ทัน แถมไม่รู้เรื่องอะไรกับเค้าเลย T_T) เลยอยากลองสรุปเรื่อง Erlang กับ Elixir นิดหน่อย&lt;/p&gt;

&lt;p&gt;NOTE: ผมใช้ macOS นะ&lt;/p&gt;

&lt;h2&gt;
  
  
  การติดตั้ง
&lt;/h2&gt;

&lt;p&gt;ทั้งสองภาษาติดตั้งได้ผ่าน brew&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Erlang
$ brew install erlang

# Elixir
$ brew install elixir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  REPL
&lt;/h2&gt;

&lt;p&gt;ทั้งสองภาษามี repl bundle มาให้ในตัว โดย Erlang นั้นจะใช้ชื่อว่า &lt;code&gt;erl&lt;/code&gt; พอเราสั่งคำสั่งนี้ก็จะเปิด repl มาให้เลย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ erl
Erlang/OTP 22 [erts-10.6.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.6.1  (abort with ^G)
1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ส่วนของ Elixir นั้นใช้ชื่อว่า &lt;code&gt;iex&lt;/code&gt; ก็จะหน้าตาคล้ายกันหน่อย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Erlang/OTP 22 [erts-10.6.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;หากถ้าอยากออกทั้งสอง shell ทำได้เหมือนกันเลยคือกด &lt;code&gt;Ctrl-C&lt;/code&gt; จากนั้นกด &lt;code&gt;a&lt;/code&gt; แล้ว Enter :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello, World
&lt;/h2&gt;

&lt;p&gt;เริ่มที่ Erlang ก่อนเลย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% hello_module.erl
-module(hello_module).
-export([hello/0]).

hello() -&amp;gt;
    io:format("~s~n", ["Hello, World"]).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Erlang มีกฎอยู่ว่าไฟล์ 1 ไฟล์จะประกอบไปด้วย 1 module และชื่อไฟล์ต้องตรงกับชื่อ module นั้นๆ ซึ่ง module จะต้องประกาศโดยใช้ &lt;code&gt;-module(&amp;lt;module_name&amp;gt;).&lt;/code&gt; เสมอ จากนั้นเราต้องบอกด้วยว่า module นี้จะ export function อะไรบ้าง สังเกตว่าจะมี &lt;code&gt;/0&lt;/code&gt; ต่อหลัง &lt;code&gt;hello&lt;/code&gt; นั้นหมายความว่าให้ export function hello ที่มีจำนวน arguments 0 ตัว เดี๋ยวไว้อธิบายทีหลังจากว่ามีทำไม&lt;/p&gt;

&lt;p&gt;ตัว function นั้นจะใช้ &lt;code&gt;-&amp;gt;&lt;/code&gt; เพื่อเปิด function body และใช้ &lt;code&gt;.&lt;/code&gt; เพื่อบอกว่าจบ function แล้ว&lt;/p&gt;

&lt;p&gt;ต่อมาคือการ compile เราสามารถ compile ได้ผ่าน &lt;code&gt;erl&lt;/code&gt; โดยใช้ function ชื่อ &lt;code&gt;c()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1&amp;gt; c(hello_module).
{ok,hello_module}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;หาก compile ผ่าน &lt;code&gt;c&lt;/code&gt; จะตอบกลับมาว่า ok กับชื่อ module ที่มัน compile ผ่านแล้ว&lt;/p&gt;

&lt;p&gt;ทีนี้มา Elixir บ้าง&lt;/p&gt;

&lt;p&gt;กฎการตั้งชื่อไฟล์จะคล้ายๆ กัน แต่นามสกุลไฟล์เป็น &lt;code&gt;.ex&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# hello_module.ex

defmodule HelloModule do
  def hello() do
    IO.puts "Hello, World"
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;การประกาศ module ของ Elixir นั้นใช้ keyword &lt;code&gt;defmodule&lt;/code&gt; ตามด้วยชื่อ module ซึ่งจะใช้ pascal case กัน &lt;/p&gt;

&lt;p&gt;การประกาศ function ใช้ keyword &lt;code&gt;def&lt;/code&gt; ตามด้วยชื่อ function และใช้ &lt;code&gt;do&lt;/code&gt; และ &lt;code&gt;end&lt;/code&gt; เพื่อเปิดและปิด function body&lt;/p&gt;

&lt;p&gt;การ compile นั้นใช้ &lt;code&gt;c()&lt;/code&gt; เหมือนกันแต่ต่างกันตรง Elixir จะใส่ชื่อไฟล์แทนชื่อ module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(1)&amp;gt; c("hello_module.ex")
[HelloModule]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  เรียก function
&lt;/h2&gt;

&lt;p&gt;ทั้งสองภาษาจะคล้ายกันโดยใช้ชื่อ module ตามด้วย function และ arguments แต่ต่างกันนิดหน่อยตรง syntax โดย Erlang ใช้ &lt;code&gt;&amp;lt;module&amp;gt;:&amp;lt;function&amp;gt;(&amp;lt;args...&amp;gt;).&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2&amp;gt; hello_module:hello().
Hello, World
ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;ส่วน Elixir ใช้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(2)&amp;gt; HelloModule.hello()
Hello, World
:ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;อีกหนึ่งความแตกต่างคือ Elixir ยอมให้เรียก function โดยไม่ใส่ &lt;code&gt;()&lt;/code&gt; ได้ เช่น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iex(2)&amp;gt; HelloModule.hello
Hello, World
:ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;พอล่ะ ง่วง zZZ&lt;/p&gt;

</description>
      <category>erlang</category>
      <category>elixir</category>
    </item>
  </channel>
</rss>
