<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Mos Programmer on Medium]]></title>
        <description><![CDATA[Stories by Mos Programmer on Medium]]></description>
        <link>https://medium.com/@mosprogrammer?source=rss-9339287ae40d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*cm9IMpOGbJQ3iarBieqtgg.png</url>
            <title>Stories by Mos Programmer on Medium</title>
            <link>https://medium.com/@mosprogrammer?source=rss-9339287ae40d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 18:36:20 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mosprogrammer/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[หัดเขียน Rust จาก Zero to Hero ตอนที่ 2]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-rust-%E0%B8%88%E0%B8%B2%E0%B8%81-zero-to-hero-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-2-42c29d44eacc?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/42c29d44eacc</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[rust]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Thu, 28 Aug 2025 14:16:43 GMT</pubDate>
            <atom:updated>2025-08-28T14:16:43.282Z</atom:updated>
            <content:encoded><![CDATA[<p>บทความก่อนหน้าเราได้รู้จัก <strong>ตัวแปร ชนิดข้อมูล การพิมพ์ค่า และ Scope </strong>กันไปแล้ว ในบทความนี้เราจะมาเรียนรู้เรื่อง <strong>การทำงานกับ Control Flow </strong>ไปด้วยกันต่อเลย</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ig2yBYfyPdaLbr1IlGPXjQ.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="https://www.facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้เราจะมาเรียนรู้ภาษา Rust กันต่อนะครับ</p><p><em>ตั้งแต่ตรงนี้ไปจะเป็นเนื้อหาที่ AI ทำมาให้นะครับ</em></p><h3>🔹 Control Flow คืออะไร?</h3><p>Control flow คือโครงสร้างที่ใช้ควบคุมลำดับการทำงานของโปรแกรม เช่น</p><ul><li>การตัดสินใจ (<strong>if / else</strong>)</li><li>การทำซ้ำ (<strong>loop / while / for</strong>)</li></ul><p>Rust มี control flow ที่ชัดเจนและปลอดภัย โดยบังคับให้เงื่อนไขต้องเป็น <strong>boolean (</strong><strong>bool)</strong> เท่านั้น</p><h4>🔹 การใช้ if</h4><pre>fn main() {<br>    let number = 7;<br><br>    if number &lt; 5 {<br>        println!(&quot;น้อยกว่า 5&quot;);<br>    } else {<br>        println!(&quot;มากกว่าหรือเท่ากับ 5&quot;);<br>    }<br>}</pre><ul><li>Rust ไม่อนุญาตให้ใช้ค่าที่ไม่ใช่ bool เป็นเงื่อนไข (เช่น 0 หรือ 1 แบบ C จะ error)</li></ul><h4>🔹 การใช้ else if</h4><pre>fn main() {<br>    let score = 85;<br><br>    if score &gt;= 90 {<br>        println!(&quot;เกรด A&quot;);<br>    } else if score &gt;= 80 {<br>        println!(&quot;เกรด B&quot;);<br>    } else if score &gt;= 70 {<br>        println!(&quot;เกรด C&quot;);<br>    } else {<br>        println!(&quot;เกรด F&quot;);<br>    }<br>}</pre><h4>🔹 ใช้ if เป็น Expression</h4><p>if สามารถคืนค่าได้ (เพราะเป็น expression)</p><pre>fn main() {<br>    let condition = true;<br>    let number = if condition { 10 } else { 20 };<br><br>    println!(&quot;number = {}&quot;, number);<br>}</pre><h4>🔹 Loop แบบไม่มีที่สิ้นสุด (loop)</h4><pre>fn main() {<br>    let mut count = 0;<br><br>    loop {<br>        count += 1;<br>        println!(&quot;รอบที่ {}&quot;, count);<br><br>        if count == 5 {<br>            break; // หยุด loop<br>        }<br>    }<br>}</pre><h4>🔹 Loop พร้อม return ค่า</h4><pre>fn main() {<br>    let mut count = 0;<br><br>    let result = loop {<br>        count += 1;<br><br>        if count == 10 {<br>            break count * 2; // คืนค่าออกจาก loop<br>        }<br>    };<br><br>    println!(&quot;Result = {}&quot;, result);<br>}</pre><h4>🔹 การใช้ while</h4><pre>fn main() {<br>    let mut number = 3;<br><br>    while number &gt; 0 {<br>        println!(&quot;{}!&quot;, number);<br>        number -= 1;<br>    }<br><br>    println!(&quot;ปล่อยจรวด!&quot;);<br>}</pre><h4>🔹 การใช้ for กับ Range</h4><pre>fn main() {<br>    for i in 1..5 { // 1 ถึง 4<br>        println!(&quot;i = {}&quot;, i);<br>    }<br><br>    for j in 1..=5 { // 1 ถึง 5<br>        println!(&quot;j = {}&quot;, j);<br>    }<br>}</pre><h4>🔹 การใช้ for กับ Collections</h4><pre>fn main() {<br>    let arr = [10, 20, 30, 40];<br><br>    for value in arr.iter() {<br>        println!(&quot;ค่า = {}&quot;, value);<br>    }<br>}</pre><h4>สรุปตอนที่ 2</h4><ul><li>if / else ใช้สำหรับการตัดสินใจ</li><li>if เป็น expression คืนค่าได้</li><li>loop → loop ไม่รู้จบ, สามารถ break พร้อมค่าได้</li><li>while → ทำงานจนกว่าเงื่อนไขจะเป็นเท็จ</li><li>for → ใช้กับ range และ collection ได้อย่างปลอดภัย</li></ul><p>ถึงตรงนี้ ถ้าใครติดปัญหาอะไรตรงไหน ก็สามารถ comment ไว้ใน Fanpage หรือ ทัก chat มาแชร์ปัญหากับผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> นะครับ หรือถ้าใครมีคำแนะนำดีๆ เกี่ยวกับภาษา Rust ก็สามารถ ทักมาบอกผมได้นะครับ</p><p>สุดท้ายนี้อยากจะฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=42c29d44eacc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[หัดเขียน Rust จาก Zero to Hero ตอนที่ 1]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-rust-%E0%B8%88%E0%B8%B2%E0%B8%81-zero-to-hero-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-1-2b2c30d9a3b2?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2b2c30d9a3b2</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[rust]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Tue, 26 Aug 2025 13:36:31 GMT</pubDate>
            <atom:updated>2025-08-26T13:36:31.955Z</atom:updated>
            <content:encoded><![CDATA[<p>หลังจากที่เราได้ติดตั้งเครื่องมือกันไปแล้ว ในบทความนี้เรามาเรียนรู้พื้นฐานของภาษา Rust ไปพร้อมๆกับผมกันเลย</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bsbtlSiuUPX-vLOzAB5CTw.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="https://www.facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้เราจะมาเจาะลึกพื้นฐานที่จำเป็น เช่น <strong>ตัวแปร ชนิดข้อมูล การพิมพ์ค่า และ Scope</strong> ซึ่งเป็นรากฐานของภาษา Rust กันครับ</p><p><em>ตั้งแต่ตรงนี้ไปจะเป็นเนื้อหาที่ AI ทำมาให้นะครับ</em></p><h3>🔹 ตัวแปร (Variables)</h3><p>ใน Rust ใช้คีย์เวิร์ด let เพื่อประกาศตัวแปร</p><pre>fn main() {<br>    let x = 5;<br>    println!(&quot;x = {}&quot;, x);<br>}</pre><p>📌 จุดสำคัญ:</p><ul><li>ตัวแปรใน Rust <strong>immutable (แก้ไขไม่ได้)</strong> ตามค่าเริ่มต้น</li><li>ถ้าต้องการเปลี่ยนค่า ต้องใช้ mut</li></ul><pre>fn main() {<br>    let mut y = 10;<br>    println!(&quot;y ก่อนเปลี่ยน = {}&quot;, y);<br>    y = 20;<br>    println!(&quot;y หลังเปลี่ยน = {}&quot;, y);<br>}</pre><h3>🔹 Shadowing</h3><p>Rust มีคุณสมบัติ <strong>Shadowing</strong> คือเราสามารถประกาศตัวแปรใหม่ที่ชื่อซ้ำกับตัวเก่าได้</p><pre>fn main() {<br>    let x = 5;<br>    let x = x + 1;  // ตัวแปรใหม่ชื่อ x แต่ค่าต่างกัน<br>    let x = x * 2;<br>    println!(&quot;x = {}&quot;, x); // ได้ค่า 12<br>}</pre><p>ข้อดีคือทำให้โค้ดอ่านง่ายขึ้น และสามารถเปลี่ยน type ของตัวแปรได้โดยไม่ต้องใช้ mut</p><h3>🔹 ชนิดข้อมูล (Data Types)</h3><p>Rust เป็นภาษา <strong>statically typed</strong> (ต้องรู้ชนิดข้อมูลก่อนคอมไพล์) แต่ส่วนใหญ่ Rust จะ <strong>infer (เดา)</strong> ชนิดข้อมูลให้เรา</p><h3>ชนิดข้อมูลหลัก</h3><p><strong>1. จำนวนเต็ม (Integer)</strong></p><ul><li>i8, i16, i32, i64, i128, isize (signed)</li><li>u8, u16, u32, u64, u128, usize (unsigned)</li></ul><pre>let a: i32 = -10;<br>let b: u32 = 100;</pre><p><strong>2. ทศนิยม (Floating Point)</strong></p><ul><li>f32, f64</li></ul><pre>let pi: f64 = 3.14159;</pre><p><strong>3. Boolean</strong></p><pre>let is_active: bool = true;</pre><p><strong>4. Character</strong></p><pre>let c: char = &#39;A&#39;;<br>let emoji: char = &#39;😎&#39;;</pre><h3>🔹 การพิมพ์ค่า (Printing)</h3><p>Rust ใช้ println! macro</p><pre>fn main() {<br>    let name = &quot;Rust&quot;;<br>    let age = 8;<br>    println!(&quot;Hello, {}! You are {} years old.&quot;, name, age);<br>}</pre><p>ผลลัพธ์:</p><pre>Hello, Rust! You are 8 years old.</pre><h3>🔹 Scope และ Shadowing</h3><p>Rust ใช้ {} กำหนด <strong>scope</strong> ของตัวแปร</p><pre>fn main() {<br>    let x = 10;<br><br>    {<br>        let x = 20; // ตัวแปร x ตัวใหม่<br>        println!(&quot;x ใน scope ย่อย = {}&quot;, x);<br>    }<br><br>    println!(&quot;x ใน scope หลัก = {}&quot;, x);<br>}</pre><p>ผลลัพธ์:</p><pre>x ใน scope ย่อย = 20<br>x ใน scope หลัก = 10</pre><h3>🔹 คอมเมนต์ (Comments)</h3><ul><li>คอมเมนต์บรรทัดเดียว → //</li><li>คอมเมนต์หลายบรรทัด → /* ... */</li><li>Doc comments → /// (ใช้กับการเขียน documentation)</li></ul><pre>fn main() {<br>    // นี่คือคอมเมนต์บรรทัดเดียว<br>    let x = 5; /* คอมเมนต์ในบรรทัด */<br>    println!(&quot;x = {}&quot;, x);<br>}</pre><h3>🎯 สรุปตอนที่ 1</h3><ul><li>let = ตัวแปร immutable, ใช้ mut ถ้าต้องการแก้ไข</li><li>Rust รองรับ <strong>Shadowing</strong></li><li>มีชนิดข้อมูลหลัก: integer, float, bool, char</li><li>ใช้ println! สำหรับพิมพ์ค่า</li><li>Scope กำหนดขอบเขตตัวแปร</li><li>คอมเมนต์ใช้ //</li></ul><p>ถึงตรงนี้ ถ้าใครติดปัญหาอะไรตรงไหน ก็สามารถ comment ไว้ใน Fanpage หรือ ทัก chat มาแชร์ปัญหากับผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> นะครับ หรือถ้าใครมีคำแนะนำดีๆ เกี่ยวกับภาษา Rust ก็สามารถ ทักมาบอกผมได้นะครับ</p><p>สุดท้ายนี้อยากจะฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2b2c30d9a3b2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[หัดเขียน Rust จาก Zero to Hero ตอนที่ 0]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-rust-%E0%B8%88%E0%B8%B2%E0%B8%81-zero-to-hero-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-0-861506072283?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/861506072283</guid>
            <category><![CDATA[rust]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Mon, 25 Aug 2025 13:01:40 GMT</pubDate>
            <atom:updated>2025-08-25T13:01:40.786Z</atom:updated>
            <content:encoded><![CDATA[<p>ก่อนอื่นเลย ผมขอแจ้งไว้ก่อนตั้งแต่ตอนนี้ว่า บทความชุดนี้ ตัวผมเองทำขึ้นเพื่อใช้สำหรับศึกษา Rust ดังนั้นบทความทั้งชุด จะเป็นเนื้อหาที่สรุปมาจาก AI โดยผมใช้ Source เป็น Document ของทาง Rust อีกทีนะครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lNX561qsNHilQSgno04BSQ.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ เหตุผลที่ตัวผมเองทำบทความชุดนี้ขึ้นมา เพราะว่าผมมี Project อยู่ตัวนึง หลังจาก ลองศึกษาค้นคว้า หาข้อมูล และวางแผนทำ Project นี้ ก็พบว่า ต้องใช้ภาษา Rust ในการพัฒนา (แต่จริงๆก็ใช้ได้อีกหลายๆภาษา แต่จะเป็นภาษาเก่าๆ กับภาษายากๆ อย่าง C++) ดังนั้นตัวผมเองที่ไม่เคยเขียน Rust มาก่อนในชีวิต ก็เลยต้องมานับ 0 กันใหม่กับภาษานี้ แต่ไหนๆก็ต้องศึกษาละ ก็เลยเอามาทำเป็นบทความด้วย เผื่อว่าใครกำลังศึกษาภาษานี้อยู่ จะได้เหมือนกับว่า เรียนไปพร้อมกับผมเลย</p><p>ในตอนที่ 0 นี้เราจะมาเริ่มติดตั้ง เครื่องมือในการพัฒนากันเลย</p><p><em>ตั้งแต่ตรงนี้ไปจะเป็นเนื้อหาที่ AI ทำมาให้นะครับ</em></p><h3>🦀 Rust คืออะไร?</h3><p>Rust เป็นภาษาโปรแกรมระบบ (system programming language) ที่ออกแบบมาเพื่อให้ เร็ว, ปลอดภัย และสามารถทำงานแบบขนาน (concurrent) ได้อย่างมั่นใจ จุดเด่นคือ ไม่มี Garbage Collector แต่ยังสามารถป้องกัน bug ประเภท memory error ได้ เช่น null pointer, dangling pointer หรือ data race</p><p>Rust ถูกใช้จริงในหลายโครงการ เช่น</p><p>Firefox → ส่วนของ rendering engine</p><p>Dropbox → ระบบเก็บไฟล์ประสิทธิภาพสูง</p><p>Cloudflare → ระบบเครือข่ายระดับโลก</p><p>Linux Kernel → เริ่มใช้ Rust เขียน driver บางส่วนแล้ว</p><p>พูดง่ายๆ Rust คือ ภาษา C/C++ เวอร์ชันปลอดภัย แต่ยังคงความเร็วไว้ครบถ้วน</p><h4>🛠️ การติดตั้ง Rust</h4><p>Rust มีตัวจัดการเวอร์ชันชื่อว่า rustup ที่ใช้ติดตั้งและอัปเดตได้สะดวก</p><p><strong>1. ติดตั้ง Rust (Linux / macOS)</strong></p><p>เปิด terminal แล้วรันคำสั่ง:</p><pre>curl - proto &#39;=https&#39; - tlsv1.2 -sSf https://sh.rustup.rs | sh</pre><p>จากนั้นกด Enter และทำตามขั้นตอน</p><p><strong>2. ติดตั้ง Rust (Windows)</strong></p><ul><li>ดาวน์โหลดจาก <a href="https://rustup.rs/">https://rustup.rs</a></li><li>ติดตั้งตาม wizard</li><li>เสร็จแล้วเปิด PowerShell / CMD เพื่อลองใช้งาน</li></ul><h4>📦 เครื่องมือสำคัญ</h4><p>เมื่อติดตั้งเสร็จแล้ว เราจะได้เครื่องมือหลักๆ 2 ตัวคือ</p><p>1. rustc → Rust compiler ใช้คอมไพล์ไฟล์ .rs ให้กลายเป็น binary</p><pre>rustc main.rs<br>./main</pre><p>2. cargo → ตัวจัดการโปรเจกต์ &amp; dependency (เหมือน npm ของ Node.js หรือ pip ของ Python) ใช้สร้างโปรเจกต์, build, run, test ได้ครบในตัวเดียว</p><pre>cargo new hello_rust<br>cd hello_rust<br>cargo run</pre><h4>📝 สร้างโปรเจกต์แรก “Hello, Rust!”</h4><p>เปิด terminal แล้วพิมพ์</p><pre>cargo new hello_rust<br>cd hello_rust</pre><p>จะได้โครงสร้างโปรเจกต์ดังนี้:</p><pre>hello_rust/<br>├── Cargo.toml # ไฟล์ config และ dependency<br>└── src/<br>└── main.rs # ไฟล์โค้ดหลัก</pre><p>เปิดไฟล์ src/main.rs จะเจอโค้ดเริ่มต้น:</p><pre>fn main() {<br>  println!(&quot;Hello, world!&quot;);<br>}</pre><p>รันโปรแกรมด้วยคำสั่ง:</p><pre>cargo run</pre><p>ผลลัพธ์ที่ได้:</p><pre>Hello, world!</pre><p>🎯 สรุปตอนที่ 0</p><ul><li>Rust เป็นภาษาที่เน้น ความเร็ว + ความปลอดภัย</li><li>ใช้ rustup เพื่อติดตั้ง Rust</li><li>รู้จักเครื่องมือ rustc และ cargo</li><li>สามารถเขียนโปรแกรมแรก “Hello, Rust!” ได้แล้ว</li></ul><p>ถึงตรงนี้ ถ้าใครติดปัญหาอะไรตรงไหน ก็สามารถ comment ไว้ใน Fanpage หรือ ทัก chat มาแชร์ปัญหากับผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> นะครับ หรือถ้าใครมีคำแนะนำดีๆ เกี่ยวกับภาษา Rust ก็สามารถ ทักมาบอกผมได้นะครับ</p><p>สุดท้ายนี้อยากจะฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=861506072283" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาเขียน Golang กันเถอะ ตอนที่ 10]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-golang-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-10-2a89ebc4fc49?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a89ebc4fc49</guid>
            <category><![CDATA[mos-programmer]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Sat, 21 Jun 2025 14:02:44 GMT</pubDate>
            <atom:updated>2025-06-21T14:02:44.340Z</atom:updated>
            <content:encoded><![CDATA[<p>เราจะมาเจาะลึกในหัวข้อที่สำคัญอย่างยิ่งในการสร้างแอปพลิเคชันที่ “แข็งแกร่ง” และ “เสถียร” นั่นคือ <strong>การจัดการข้อผิดพลาด (Error Handling)</strong> ในสไตล์ของ Go ครับ เราจะมาดูว่าปรัชญาของ Go ที่มองว่า <strong>“Error คือค่าๆ หนึ่ง”</strong> นั้นทำงานอย่างไร และเราจะจัดการกับมันอย่างถูกวิธีได้อย่างไร</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KYLNgofcoiwx51DSBQA77A.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้เราจะมาเรียนรู้วิธีการเขียนโปรแกรมที่พร้อมรับมือกับสถานการณ์เหล่านี้อย่างสง่างาม ด้วยปรัชญา <strong>การจัดการข้อผิดพลาด (Error Handling)</strong> ในสไตล์ของ Go และพบกับคีย์เวิร์ดสุดสะดวกอย่าง <strong>defer</strong> ที่จะช่วยให้เราไม่ลืมจัดการทรัพยากรที่สำคัญครับ</p><h4><strong>Error Handling </strong>ใน Go เมื่อ “Error คือค่าๆ หนึ่ง”</h4><p>สิ่งแรกที่ต้องเข้าใจคือ Go มอง Error แตกต่างจากภาษาอื่นโดยสิ้นเชิง <strong>ภาษาอื่น (เช่น Java, C#, Python) </strong>มักจะใช้ระบบ <strong>Exception Handling (</strong><strong>try-catch)</strong> ซึ่งมองว่า Error คือ &quot;เหตุการณ์พิเศษ&quot; ที่จะหยุดการทำงานปกติและ &quot;โยน&quot; (Throw) ออกไปให้โค้ดส่วนอื่นรับไปจัดการ</p><p><strong>ภาษา Go</strong> มองว่า <strong>Error คือ “ค่า” (Value) ธรรมดาๆ ค่าหนึ่ง</strong> เหมือนกับตัวเลขหรือข้อความ มันไม่ใช่เหตุการณ์พิเศษ แต่เป็นหนึ่งในผลลัพธ์ที่ <em>คาดว่าจะเกิดขึ้นได้</em> ในการทำงานปกติ</p><p><strong>เปรียบเทียบกับการทำอาหาร</strong></p><p><strong>try-catch:</strong> เหมือนการทำอาหารโดยคิดว่าวัตถุดิบทุกอย่างจะดีเลิศ ถ้าบังเอิญเจอไข่เน่า (Exception) กระบวนการทั้งหมดจะหยุดชะงักทันที แล้วคุณต้องไปจัดการกับความวุ่นวายในบล็อก catch แทน</p><p><strong>Go:</strong> เหมือนเชฟมืออาชีพที่รู้ว่าไข่บางฟองอาจจะเน่าได้ <strong>ขั้นตอนการเช็คไข่จึงถูกรวมอยู่ในสูตรอาหารปกติ</strong>: “ตอกไข่ใส่ถ้วยเล็กๆ ก่อน -&gt; <strong>เช็คว่าไข่เน่าหรือไม่ (</strong><strong>if err != nil)</strong> -&gt; ถ้าเน่าให้ทิ้งไป ถ้าดีค่อยเทใส่ชามผสม&quot;</p><p>การตรวจสอบ Error ใน Go จึงเป็นส่วนหนึ่งของ Flow การทำงานปกติ ไม่ใช่ข้อยกเว้นครับ</p><p><strong>Workflow การจัดการ Error ที่ถูกต้อง</strong></p><p>เมื่อเข้าใจปรัชญาแล้ว เรามาดูขั้นตอนการทำงานกับ Error ที่โปรแกรมเมอร์ Go ใช้กันเป็นมาตรฐาน</p><p><strong>Step 1: เรียกฟังก์ชันและรับค่า </strong><strong>error<br></strong>ฟังก์ชันที่อาจทำงานพลาดได้จะคืนค่า error เป็นค่าสุดท้ายเสมอ</p><pre>file, err := os.Open(&quot;my_file.txt&quot;)</pre><p><strong>Step 2: ตรวจสอบทันที! (The Golden Rule)<br></strong>นี่คือกฎทองคำ: <strong>หลังจากเรียกฟังก์ชันที่คืนค่า error ให้ตรวจสอบค่า </strong><strong>err ทันที</strong></p><pre>file, err := os.Open(&quot;my_file.txt&quot;)<br>if err != nil {<br>    // ถ้า err ไม่ใช่ nil แสดงว่ามีข้อผิดพลาดเกิดขึ้น!<br>    // เราต้องจัดการมันตรงนี้<br>}</pre><p><strong>Step 3: จัดการ Error อย่าแค่ Print หรือสั่ง Panic!<br></strong>มือใหม่มักจะจัดการ Error ด้วยการ fmt.Println(err) หรือ panic(err) ซึ่งส่วนใหญ่แล้วเป็นวิธีที่ไม่ค่อยดีเท่าไหร่ครับ</p><ul><li><strong>ทำไม </strong><strong>Println ถึงไม่ดี?</strong> เพราะมันแค่พิมพ์ข้อความออกหน้าจอ แต่ไม่ได้หยุดการทำงานส่วนที่เหลือซึ่งอาจต้องอาศัยผลลัพธ์จากส่วนที่พลาดไป ทำให้โปรแกรมอาจทำงานผิดพลาดต่อไป</li><li><strong>ทำไม </strong><strong>panic ถึงไม่ดี?</strong> เพราะมันทำให้ทั้งโปรแกรม &quot;ล่ม&quot; และหยุดทำงานทันที ควรใช้ panic ในกรณีที่โปรแกรมไม่สามารถทำงานต่อได้จริงๆ เท่านั้น (เช่น ไม่สามารถเชื่อมต่อฐานข้อมูลหลักได้ตั้งแต่เริ่ม)</li></ul><p><strong>Step 4: (ข้อนี้สำคัญที่สุด) เพิ่มบริบทและ Return<br></strong>วิธีจัดการ Error ที่ดีที่สุดในฟังก์ชันส่วนใหญ่คือ <strong>การส่งต่อ error กลับไปยังฟังก์ชันที่เรียกเรามา พร้อมกับเพิ่ม “</strong>บริบท<strong>” </strong>ว่า error นี้เกิดขึ้นตอนที่เรากำลังพยายามทำอะไร</p><p>เราใช้ fmt.Errorf และ %w (verb สำหรับ wrap error) ในการเพิ่มบริบท</p><p><strong>ตัวอย่าง: </strong>สมมติเรามีฟังก์ชัน readConfig ที่ต้องเปิดไฟล์ config.json</p><pre>func readConfig() error {<br>    file, err := os.Open(&quot;config.json&quot;)<br>    if err != nil {<br>        // ถ้าเราแค่ส่งต่อ error เดิมๆ คนเรียกจะไม่รู้ว่าเกิดจากอะไร<br>        // return err <br><br>        // ควรเพิ่มบริบทว่าเกิดอะไรขึ้น แล้ว wrap error เดิมไปด้วย<br>        return fmt.Errorf(&quot;ไม่สามารถอ่านไฟล์ config ได้: %w&quot;, err)<br>    }<br>    defer file.Close()<br>    <br>    // ... ทำงานกับไฟล์ต่อไป ...<br>    return nil // คืนค่า nil ถ้าไม่มี error<br>}<br><br>func main() {<br>    err := readConfig()<br>    if err != nil {<br>        // error ที่ได้รับที่ main จะมีข้อความเต็มๆ ว่า<br>        // &quot;ไม่สามารถอ่านไฟล์ config ได้: open config.json: no such file or directory&quot;<br>        // แค่นี้เราก็จะสามารถ Debug ได้ง่ายขึ้นมากแล้ว<br>        log.Fatal(err) <br>    }<br>}</pre><p>การเพิ่มบริบทแบบนี้ ทำให้เมื่อเกิดปัญหาที่ main เราจะเห็นร่องรอยของปัญหาทั้งหมด ไม่ใช่แค่ error สุดท้ายที่ปลายเหตุ ทำให้การแก้ไขปัญหาง่ายขึ้นมหาศาล</p><h4>defer คืออะไร? - ไม่ใช่ &quot;ทำทันที&quot; แต่คือ &quot;เดี๋ยวจะทำแน่ๆ</h4><p>defer คือคำสั่งที่ใช้ &quot;แปะ&quot; ฟังก์ชันไว้ก่อน โดยบอกกับ Go ว่า :</p><p>“ฟังก์ชันที่ฉันแปะ defer ไว้นี้ <strong>ยังไม่ต้องทำตอนนี้</strong> นะ แต่ฉันขอสั่งจองไว้ก่อนว่า <strong>นายต้องทำให้ฉันแน่ๆ</strong> ในวินาทีสุดท้ายก่อนที่ฟังก์ชันหลักที่ครอบอยู่จะจบการทำงาน&quot;</p><p>เปรียบเทียบให้เห็นภาพที่สุด: ให้นึกถึงการไปร้านอาหาร</p><ul><li>คุณเดินเข้าร้านอาหารแล้วสั่งอาหาร (เปรียบเหมือนการเปิดไฟล์ หรือเชื่อมต่อฐานข้อมูล)</li><li>เรารู้ตัวว่ากินเสร็จยังไงก็ต้อง “จ่ายเงิน” แน่นอน แต่ยังไม่ใช่ตอนนี้ เราก็เลยบอกพนักงานเสิร์ฟไว้ล่วงหน้าเลยว่า <strong>“เดี๋ยวตอนผมจะกลับ ช่วยเอาบิลมาเก็บเงินด้วยนะ”</strong> (นี่คือการ defer ครับ)</li><li>จากนั้นคุณก็นั่งกินอาหารไปตามปกติ…</li><li>เมื่อคุณกินเสร็จและกำลังจะลุกออกจากร้าน (เปรียบเสมือนเรากำลังจะ return จากฟังก์ชัน) พนักงานเสิร์ฟก็จะเดินเอาบิลมาให้เราทันทีตามที่ได้สั่งพนักงานเสิร์ฟไว้</li></ul><p>defer ก็คือการ <strong>&quot;สั่งงานที่จะทำตอนจบ&quot;</strong> นั่นเองครับ</p><h4><strong>ทำไม </strong><strong>defer ถึงเป็นพระเอก? (แก้ปัญหาอะไร)</strong></h4><p>defer คือพระเอกในการ <strong>&quot;คืนทรัพยากร&quot; (Resource Cleanup)</strong> เช่น การปิดไฟล์, การปิดการเชื่อมต่อเน็ตเวิร์ก/ฐานข้อมูล</p><p><strong>ยกตัวอย่างสถานการณ์ที่ “ไม่มี” </strong><strong>defer:</strong></p><pre>func processFile() error {<br>    file, err := os.Open(&quot;data.txt&quot;)<br>    if err != nil {<br>        return err // &lt;&lt; จุดที่ 1 ที่อาจออกจากฟังก์ชัน<br>    }<br><br>    // ... ทำงานกับไฟล์ 50 บรรทัด ...<br><br>    if someCondition {<br>        file.Close() // &lt;&lt; ต้องไม่ลืมปิดไฟล์ตรงนี้<br>        return someError<br>    }<br><br>    // ... ทำงานกับไฟล์อีก 50 บรรทัด ...<br><br>    file.Close() // &lt;&lt; และต้องไม่ลืมปิดไฟล์ตรงนี้ด้วย<br>    return nil<br>}</pre><p><strong>ปัญหา:</strong></p><ul><li>โค้ดดูรก เพราะต้องมี file.Close() หลายที่</li><li><strong>เสี่ยงมากที่จะลืม!</strong> ถ้าเราเพิ่มเงื่อนไข if แล้ว return ไปอีกจุด แต่ลืมใส่ file.Close() ก็จะเกิดปัญหา &quot;Resource Leak&quot; ทันที</li></ul><p><strong>ทีนี้ลองมาดูสถานการณ์ที่ “มี” </strong><strong>defer:</strong></p><pre>func processFile() error {<br>    file, err := os.Open(&quot;data.txt&quot;)<br>    if err != nil {<br>        return err<br>    }<br>    // บอก Go ทันทีหลังเปิดไฟล์สำเร็จว่า &quot;เดี๋ยวตอนจบ ช่วยปิดไฟล์ให้ด้วยนะ&quot;<br>    defer file.Close()<br><br>    // ... ทำงานกับไฟล์ 100 บรรทัดได้อย่างสบายใจ ...<br>    <br>    if someCondition {<br>        return someError // ไม่ต้องห่วง defer จะทำงานให้เอง<br>    }<br><br>    // ... ไม่ว่าฟังก์ชันจะจบตรงไหน หรือมีกี่ return ...<br>    // ... file.Close() จะถูกเรียกทำงานให้เองเสมอ 100%<br>    return nil<br>}</pre><p><strong>ข้อดี:</strong></p><ul><li><strong>โค้ดสะอาด:</strong> Close อยู่ที่เดียว ติดกับ Open อ่านง่ายมาก</li><li><strong>ปลอดภัย:</strong> ไม่มีทางลืมปิดไฟล์แน่นอน</li><li><strong>บำรุงรักษาง่าย:</strong> จะเพิ่ม return อีกกี่จุดก็ได้ ไม่ต้องกังวล</li></ul><h4>กฎของ defer: LIFO (Last-In, First-Out)</h4><p>ถ้าในหนึ่งฟังก์ชันมี defer หลายอัน มันจะทำงานเหมือน <strong>&quot;กองจาน&quot; </strong>ซึ่ง “จานที่วางไว้บนสุด (defer อันล่าสุด) จะถูกหยิบออกไปก่อน”</p><p><strong>ตัวอย่าง:</strong></p><pre>func main() {<br>    fmt.Println(&quot;เริ่มนับ...&quot;)<br><br>    defer fmt.Println(&quot;1&quot;) // อันนี้จะทำงานเป็นอันดับ 3 (อันแรกสุด)<br>    defer fmt.Println(&quot;2&quot;) // อันนี้จะทำงานเป็นอันดับ 2<br>    defer fmt.Println(&quot;3&quot;) // อันนี้จะทำงานเป็นอันดับ 1 (อันล่าสุด)<br><br>    fmt.Println(&quot;...นับเสร็จ!&quot;)<br>}</pre><p><strong>ผลลัพธ์ที่ได้:</strong></p><pre>เริ่มนับ...<br>...นับเสร็จ!<br>3<br>2<br>1</pre><p>defer เป็นเครื่องมือที่เรียบง่ายแต่ช่วยให้โค้ด Go ของเราปลอดภัยและสะอาดขึ้นอย่างมหาศาลครับ</p><p>ตอนนี้ เราได้เรียนรู้สองแนวคิดสำคัญที่ทำให้โค้ด Go ของเราแข็งแกร่งและพร้อมใช้งานจริง</p><ul><li><strong>Error Handling</strong> สอนให้เราจัดการกับความผิดพลาดอย่างเป็นระบบ</li><li><strong>defer</strong> เป็นเครื่องมือช่วยชีวิตที่ทำให้เราจัดการทรัพยากรได้อย่างปลอดภัยและไม่ตกหล่น</li></ul><p>เราได้ครอบคลุมเครื่องมือหลักๆ สำหรับการเขียนโปรแกรมทั่วไปใน Go เกือบทั้งหมดแล้ว ในตอนต่อไป เราจะก้าวเข้าสู่โลกที่เป็น “หัวใจ” และเป็นความสามารถที่โดดเด่นที่สุดของ Go ที่ทำให้มันแตกต่างจากภาษาอื่น นั่นคือ <strong>Concurrency</strong> หรือการเขียนโปรแกรมให้ทำงานหลายๆ อย่างพร้อมกันได้อย่างง่ายดายและปลอดภัยด้วย <strong>Goroutines</strong> และ <strong>Channels</strong> ครับ</p><p>สำหรับใครที่ติดปัญหา หรือมีข้อสงสัยเกี่ยวกับการเขียน <strong>Go</strong> ก็สามารถทักไปหาผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a><strong> </strong>ได้นะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a89ebc4fc49" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาเขียน Golang กันเถอะ ตอนที่ 9]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-golang-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-9-540b705ca39a?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/540b705ca39a</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Wed, 18 Jun 2025 12:50:55 GMT</pubDate>
            <atom:updated>2025-06-18T12:50:55.799Z</atom:updated>
            <content:encoded><![CDATA[<p>จะเกิดอะไรขึ้นถ้าเราอยากจะเขียนฟังก์ชันที่สามารถทำงานกับ Type ที่แตกต่างกันหลายๆ แบบได้ ตราบใดที่ Type เหล่านั้นมี “ความสามารถ” บางอย่างร่วมกัน?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VhYFijAyZi3xJQtteZnlyw.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้เราจะมารู้จักสิ่งที่เรียกว่า Interface กันครับ</p><h4>Interface คืออะไร?</h4><p>Interface เปรียบเสมือน <strong>“สัญญา” </strong>ในโลก Programming ครับ มันไม่ได้บอกว่า “สิ่งนั้นคืออะไร” แต่จะบอกว่า “สิ่งนั้น<strong>ทำอะไรได้บ้าง</strong>”</p><p>เปรียบได้กับสิ่งที่เข้าใจง่ายที่สุดอย่างเช่น “เต้ารับไฟฟ้า” ครับ</p><p>เต้ารับไฟฟ้า (The Socket) = คือ Interface เต้ารับไฟฟ้ากำหนด “สัญญา” หรือ “กฎ” เอาไว้ว่า “ถ้าจะเสียบกับฉันได้ อุปกรณ์นั้นจะต้องมี <strong>ปลั๊กขาแบน 2 ขา</strong>” เต้ารับไม่สนใจเลยว่าอุปกรณ์นั้นจะเป็นพัดลม, ทีวี, ที่ชาร์จมือถือ หรือโคมไฟ ขอแค่มีปลั๊กที่ตรงตามกฎก็พอ</p><p>ปลั๊กเครื่องใช้ไฟฟ้า (The Plug) = คือ Type ที่ทำตามสัญญา ปลั๊กของพัดลม (มีขาแบน 2 ขา) เท่ากับว่าทำตามสัญญา สามารถเสียบได้ ปลั๊กคอมพิวเตอร์มี 3 ขา เท่ากับว่าไม่เป็นไปตามสัญญา ก็ไม่สามารถนำมาเสียบได้นั่นเองครับ</p><p>ทีนี้ตอนเอาไปเขียนใน Code ถ้าเรากำหนด Interface Shape ว่าต้องมี method Area() และเรามี Struct Circle ที่มี method Area() และมี Struct Rectangle ที่มี methodArea() <strong>Go จะถือว่าทั้ง </strong><strong>Circle และ </strong><strong>Rectangle เป็น </strong><strong>Shape โดยอัตโนมัติ</strong> เราไม่จำเป็นต้องเขียนบอกโปรแกรมว่า Circle implements Shape เหมือนในภาษาอื่น</p><p><strong>ตัวอย่างโค้ดสั้นๆ</strong></p><pre>// 1. สร้าง &quot;สัญญา&quot; (Interface)<br>// สัญญาคือ: ต้องหาพื้นที่ได้ (Area())<br>type Shape interface {<br>    Area() float64<br>}<br><br>// 2. สร้าง Type ที่จะมาทำตามสัญญา<br>type Circle struct { Radius float64 }<br>type Rectangle struct { Width, Height float64 }<br><br>// 3. ทำให้ Type ทำตามสัญญา (แค่สร้าง Method ให้ครบ)<br>func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius }<br>func (r Rectangle) Area() float64 { return r.Width * r.Height }<br><br><br>// 4. ฟังก์ชันที่รับ &quot;สัญญา&quot; เป็น Input<br>// ฟังก์ชันนี้ไม่สนว่าจะเป็นวงกลมหรือสี่เหลี่ยม ขอแค่ทำตามสัญญา (หาพื้นที่ได้) ก็พอ<br>func printArea(s Shape) {<br>    fmt.Printf(&quot;พื้นที่คือ %.2f\n&quot;, s.Area())<br>}<br><br>func main() {<br>    myCircle := Circle{Radius: 5}<br>    myRectangle := Rectangle{Width: 4, Height: 6}<br><br>    // เราสามารถส่ง &quot;อะไรก็ได้&quot; ที่ทำตามสัญญา Shape เข้าไปได้<br>    printArea(myCircle)<br>    printArea(myRectangle)<br>}</pre><p>เห็นมั้ยครับว่าเรา <strong>ไม่ได้เขียนที่ไหนเลยว่า </strong><strong>Rectangle implements Shape</strong> หรืออะไรทำนองนั้น ภาษา Go จะรู้โดยอัตโนมัติว่าถ้า Type ไหนมี Method ทั้งหมดตามที่ Interface กำหนดไว้ ก็จะถือว่า Type นั้นทำตามสัญญาของ Interface ที่กำหนดไว้ทันที เราเรียกสิ่งนี้ว่า <strong>Implicit Implementation</strong></p><p>นอกจากนี้ใน Go มี Interface พิเศษที่เรียกว่า “Empty Interface” ซึ่งเขียนว่า interface{} คือ Interface ที่ <strong>ไม่มี Method ที่บังคับให้ต้องทำตามเลย</strong> ผลก็คือ <strong>Type ทุกชนิดใน Go ทำตามสัญญาของ Empty Interface โดยอัตโนมัติ</strong></p><p>เราจึงใช้ interface{} เพื่อสร้างฟังก์ชันที่สามารถรับค่าเป็นอะไรก็ได้ แบบนี้ครับ</p><pre>func printAnything(value interface{}) {<br>    fmt.Printf(&quot;ค่าที่รับมาคือ &#39;%v&#39; และเป็นชนิด %T\n&quot;, value, value)<br>}<br><br>func main() {<br>    printAnything(42)<br>    printAnything(&quot;hello&quot;)<br>    printAnything(true)<br>    printAnything(Rectangle{Width: 3, Height: 4})<br>}</pre><p><strong>ข้อควรระวัง:</strong> interface{} ให้ความยืดหยุ่นสูง แต่ก็ต้องแลกมากับการที่เราไม่รู้ Type ที่แท้จริงของข้อมูล ซึ่งการจะนำไปใช้งานต่อต้องใช้เทคนิคขั้นสูงขึ้นที่เรียกว่า &quot;Type Assertion&quot;</p><p>นอกจากนี้สิ่งที่ต้องระวังอย่างมากอีกอย่างนึงก็คือ nil ซึ่งมักจะมาพร้อมกับ Empty Interface เสมอครับ</p><h4>nil คืออะไร?</h4><p>nil (อ่านว่า <em>นิล</em>) ในภาษา Go คือ <strong>&quot;ค่าว่าง&quot;</strong> หรือ <strong>&quot;ความไม่มีอยู่&quot;</strong> สำหรับข้อมูลบางประเภทครับ แล้วข้อมูลประเภทไหนที่สามารถเป็น nil ได้บ้าง?</p><ul><li><strong>Slice (</strong><strong>[]string)</strong>: Slice ที่ยังไม่ได้ถูกสร้างขึ้น</li><li><strong>Map (</strong><strong>map[string]int)</strong>: Map ที่ยังไม่ได้ถูกสร้างขึ้น</li><li><strong>Pointer (</strong><strong>*int)</strong>: ตัวชี้ที่ยังไม่ได้ชี้ไปที่ข้อมูลใดๆ</li><li><strong>Interface (</strong><strong>interface{})</strong>: Interface ที่ยังไม่มีการกำหนดค่าหรือ Type ใดๆ</li><li><strong>Function (</strong><strong>func())</strong>: ตัวแปรฟังก์ชันที่ยังไม่ได้กำหนดค่าเป็นฟังก์ชันใดๆ</li><li><strong>Channel (</strong><strong>chan int)</strong>: Channel ที่ยังไม่ได้ถูกสร้างขึ้น</li></ul><p><strong>ข้อควรระวัง </strong>: “nil pointer dereference” (Panic!) นี่คือ Error ที่เจ็บปวดที่สุดสำหรับมือใหม่ มันเกิดขึ้นเมื่อเราพยายาม <strong>ใช้งานข้อมูลจากตัวแปรที่เป็น </strong><strong>nil</strong></p><p>ดังนั้น Type ใดๆ ที่มี Method ทั้งหมดตามที่ Interface กำหนดไว้ แต่ค่าที่เก็บไว้เป็น nil เราจึงจำเป็นจะต้องระวังเป็นพิเศษ เพื่อไม่ให้เกิด Panic ขึ้นนั่นเองครับ</p><p>สรุปเลย Interface คือแนวคิดที่ช่วยให้เราเขียนโค้ดที่ยืดหยุ่น, ไม่ผูกติดกัน (Decoupled), และนำกลับมาใช้ใหม่ได้ง่าย โดยเปลี่ยนมุมมองจากการเขียนโค้ดที่อิงกับ “มันคืออะไร” (Concrete Type) ไปเป็นการอิงกับ “มันทำอะไรได้บ้าง” (Behavior)</p><p>เราได้เดินทางมาครอบคลุมแกนหลักของภาษา Go เกือบทั้งหมดแล้ว ตั้งแต่พื้นฐาน, โครงสร้างข้อมูล, ไปจนถึงการจัดระเบียบโค้ด ในตอนต่อไป เราจะมาเจาะลึกในหัวข้อที่สำคัญอย่างยิ่งในการสร้างแอปพลิเคชันที่เสถียร นั่นคือ <strong>การจัดการข้อผิดพลาด (Error Handling)</strong> ในสไตล์ของ Go และการใช้ defer เพื่อช่วยจัดการทรัพยากรให้สะอาดปลอดภัยครับ</p><p>สำหรับใครที่ติดปัญหา หรือมีข้อสงสัยเกี่ยวกับการเขียน <strong>Go</strong> ก็สามารถทักไปหาผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a><strong> </strong>ได้นะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=540b705ca39a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาวิเคราะห์ หน้าจอง Nintendo Switch 2 กัน]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B8%A7%E0%B8%B4%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B2%E0%B8%B0%E0%B8%AB%E0%B9%8C-%E0%B8%AB%E0%B8%99%E0%B9%89%E0%B8%B2%E0%B8%88%E0%B8%AD%E0%B8%87-nintendo-switch-2-%E0%B8%81%E0%B8%B1%E0%B8%99-dba4321492b5?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/dba4321492b5</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[trends]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[nintendo-switch]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Tue, 17 Jun 2025 17:46:19 GMT</pubDate>
            <atom:updated>2025-06-17T17:46:19.364Z</atom:updated>
            <content:encoded><![CDATA[<p>ล่มได้ยังไง ทำไมถึงล่ม คนบ่นเยอะจัง บทความนี้เรามาลองแงะดู แล้วก็เดาไปพร้อมๆกันละกันนะครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4WIUMo8xFyW_9ZvqRDuGtQ.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ บทความนี้สร้างขึ้นเพื่อให้ความรู้ และความบันเทิงนะครับ ถ้าใครไม่ซีเรียสก็อ่านขำๆได้นะครับ</p><p>พอดีช่วงนี้มี Event จอง Nintendo Switch 2 กัน แต่ผมก็ไม่ได้สนใจ เนื่องจากว่ายังหาเหตุผลให้ไปซื้อมาเล่นไม่ได้ เครื่องเก่าที่มีอยู่ก็แทบไม่ได้เล่นเลย ทำแต่งาน เวลาว่างก็แทบไม่มีละ</p><p>แต่พอดีว่าทั้งใน Social Media บวกกับน้องๆในที่ทำงาน บ่นๆกันเรื่องจอง Nintendo Switch 2 ผมก็เลยลองเข้าไปจองกับเค้าบ้าง แต่ก็แห้วตลอดเลย (แหะๆ) ก็เลยแอบไปลองถามในกลุ่ม ไปสอดส่องหาข่าวสารนิดนึง</p><p>ต้องบอกก่อนเลยว่า ก่อนหน้าที่จะมาสืบข่าวเรื่องนี้ ผมเองไม่ได้ติดตามอะไรเลย เรื่องการจองเครื่องก็สอบถามใน Social ก่อนที่จะมาเขียนบทความนี่แหละครับ เท่าที่ได้เรื่องมาก็น่าจะประมาณว่า</p><p>พอกดเข้าตาม Link ที่ Synnex เองแปะมาให้ ก็จะเข้าสู่หน้าเลือกตัวแทนจำหน่าย เสร็จแล้วก็จะไปอยู่ในหน้ารอคิว พอได้คิวก็จะเข้าสู่หน้าสำหรับกรอกรายละเอียดข้อมูลส่วนตัว Email ที่อยู่ เลือกรุ่น เลือกสาขาใกล้บ้าน และเลือกวันที่จะเข้ารับ โดยกระบวนการทั้งหมด จะมีการจำกัดเวลาเอาไว้ ถ้าทำเสร็จไม่ทันก็จะชวดไป คร่าวๆก็ประมาณนี้</p><p>ซึ่งถ้าเป็นระบบทั่วไป ประมาณนี้ มันก็ไม่น่าจะล่มถูกมั้ยครับ แล้วปัญหามันอยู่ที่ตรงไหนล่ะ เรามานั่งวิเคราะห์กันครับ</p><p><strong><em>เนื้อหาหลังจากนี้ขอแจ้งเตือนไว้ก่อนว่าผมเดาล้วนๆนะครับ เนื่องจากว่าผมเองก็ไม่ได้เห็นระบบจริง ไม่ได้เข้าไปหน้าจองกับเค้าด้วย เข้าไปได้ถึงแค่ตอนหน้ารอเท่านั้นเอง ดังนั้นเนื้อหาส่วนใหญ่ก็จะเอามาจากการบอกเล่าปากต่อปาก บวกกับการมโนของผมเองนะครับ</em></strong></p><p>เท่าที่ผมลองวิเคราะห์ และลองวาดออกมา Flow ก็น่าจะประมาณนี้ ถ้าใครมองว่าต้องปรับตรงไหนเพิ่ม ก็ Comment เพิ่มเติมใน Facebook ละกันนะครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Eg1aqYYBgeBDDnm368WdDg.png" /></figure><p><strong>STEP 1 — </strong>ลูกค้าเข้าหน้าเว็บตาม Link ที่ได้รับมา</p><p><strong>STEP 2 — </strong>ลูกค้าเลือก Dealer</p><p><strong>STEP 3 — </strong>หน้าเว็บจะส่งต่อไปยังหน้ารอคิว</p><p><strong>STEP 4 — </strong>ในหน้ารอคิว เริ่มต้นก็จะทำการเรียก api เพื่อทำการเช็คคิวก่อน ว่ามีใครรอคิวก่อนหน้าหรือป่าว ถ้ามีก็จะมีการตั้งเวลาไว้ประมาณนึง แล้วก็ค่อยไปยิง api เพื่อเช็คใหม่อีกรอบ วนๆไปแบบนี้จนกว่าจะถึงคิวของลูกค้า</p><p><strong>STEP 5 — </strong>พอถึงคิวลูกค้าก็จะเข้าสู่หน้าจอง ซึ่งหน้าจองก็จะโหลดข้อมูลต่างๆมาให้ลูกค้าได้กรอกข้อมูลสำหรับจองคิว ทั้งข้อมูลสาขา และข้อมูลเครื่องเกม</p><p><strong>STEP 6 — </strong>ลูกค้ากรอกข้อมูลแล้วกด Submit เพื่อส่งข้อมูลไปยัง Backend</p><p><strong>STEP 7 </strong>— ในส่วนของ Backend ก็จะทำการประมวลผล ตามเงื่อนไขที่ตั้งไว้ ถ้าไม่ติดเงื่อนไขอะไรก็จะสามารถส่ง email ออกไปได้</p><p>ทีนี้มาเดากันต่อครับว่าปัญหาสามารถเกิดขึ้นได้ที่ Step ไหนบ้าง</p><p>เท่าที่ผมลองคิดๆดู <strong>STEP 4 </strong>ก็มีความเป็นไปได้ที่จะเกิด การ query ข้อมูลอย่างหนักทำให้ database รับภาระเยอะ เพราะว่าจะมีการส่ง request จากทางฝั่ง frontend ส่งไปเป็นระยะๆ ซึ่งตรงนี้ จะต้อง คูณด้วยจำนวน browser ที่เปิดดูหน้านี้อยู่ด้วย แต่ตรงนี้ก็สามารถแก้ไขได้โดยการใช้ cache storage อย่างเช่น redis หรือ dynamoDB มารองรับตรงนี้แทน ทำให้ไม่ต้องไปแตะ database บ่อยๆ ซึ่งถ้าใช้วิธีนี้ สิ่งที่ตามมาก็น่าจะเป็นเรื่องของ Resource ที่จัดสรรค์ให้กับตัว api ว่าเพียงพอต่อจำนวน request มั้ย ซึ่งถ้ายอมเพิ่ม resource ให้ หรืออาจจะเตรียมไว้ให้สามารถ scale ได้ตั้งแต่แรก <strong>STEP 4 </strong>ก็น่าจะผ่านไป</p><p>STEP ที่มีความเป็นไปได้ถัดไปก็น่าจะเป็น <strong>STEP 5 </strong>เนื่องจากว่าจะต้องดึงข้อมูลสาขา ต่างๆออกมา ซึ่งก็จะมี Logic ในการดึงข้อมูลตรงนี้ด้วย อาจจะต้องเริ่มดูจากส่วนของ database ก่อนเลยว่า เก็บข้อมูลสาขาลง database แบบไหน เป็น sql หรือ nosql ข้อมูลสาขา และข้อมูลจำนวนเครื่อง หรือจำนวนโควต้าต่างๆ เก็บรวมกันอยู่ใน table หรือ collection เดียวกัน หรือว่าอยู่ต่างที่กัน ต้องจับมา join กันหรือป่าว หรือว่าจริงๆแล้วแยกเป็น microservice ข้อมูลสาขาเก็บที่นึง ข้อมูลโควต้าเก็บอีกที่นึง ซึ่งอาจจะต้องแยกเป็นแต่ละหัวข้อก่อน</p><ul><li>ในกรณีที่เก็บลง sql และอยู่ table เดียวกัน ก็อาจจะเป็นเพราะมีการ update ข้อมูลอยู่ตลอดเวลาทำให้ database รับภาระหนักเกินไป อาจจะต้องใช้ cache storage มาเก็บข้อมูลในส่วนที่ต้องทำการดึงไปใช้ แทนการแตะ database ตรงๆแทน</li><li>แต่ถ้าเป็นการเก็บลง nosql อันนี้อาจจะต้องดูต่อว่า index กำหนดได้ถูกต้องมั้ย data ที่เก็บลง database มี field ที่ต้องการครบหรือป่าว หรือว่าเก็บไว้แยก collection กัน ถ้าแยก collection อันนี้อาจจะต้องรื้อ data structure ใหม่ แล้วทำการรวม data ให้มาอยู่ในก้อนเดียวกัน เพื่อไม่ให้เกิดการ join ขึ้น เนื่องจาก การ join กันใน nosql เป็นอะไรที่ทำงานได้ช้ามากๆ</li><li>หรือถ้าเก็บใน sql แต่แยก table กัน อันนี้อาจจะต้องดูว่า index ถูกต้องมั้ย มี index สำหรับ join และ index สำหรับ where ครบหรือป่าว หรือจะให้ดีก็เก็บลง cache storage ไปเลยจะดีกว่า</li><li>แต่ถ้าหากว่าเป็นการดึงข้อมูลจาก database แล้วเอามา get api จาก microservice อื่นๆอีกที หรือไม่ว่าจะเป็นการ get ข้อมูลจาก api ตัวนึง แล้วเอา data มารวมกับ api อีกตัวนึง อันนี้ยิ่งจำเป็นจะต้องทำเป็น cache storage ด่วนๆเลยเพราะวิธีการนี้ ทำให้ระบบเสียเวลาซ้ำซ้อนเข้าไปอีกนั่นเอง</li><li>แต่ถ้าหากว่าทั้งหมดทั้งมวลเก็บลง cache storage ไปหมดแล้ว แต่ก็ยังช้าอยู่ก็อาจจะต้องพิจารณาอัด resource ให้แทน ให้เพียงพอต่อการรับ load ที่เข้ามา</li></ul><p>แต่ถ้าลองดูแล้วปรากฎว่าตรงนี้ยังไม่ใช่ ก็จะเหลือ STEP สุดท้าย <strong>STEP 7 </strong>ในการเช็ค เงื่อนไขต่างๆ ว่าในการเช็คแต่ละเงื่อนไข มี Logic ที่ซับซ้อนหรือป่าว หรือว่ามีการดึงข้อมูลที่ไม่จำเป็นออกมาด้วยมั้ย เพราะเท่าที่เข้าใจจาก<strong>การเดา(ขอย้ำว่าจากการเดานะครับ) </strong>STEP นี้จะเป็นการเช็คเงื่อนไขต่างๆซ้ำอีกรอบ ก่อนจะเอาลง database ถ้าไม่ได้ดึงข้อมูลเกินกว่าที่จำเป็นก็จะมีอีกเรื่องก็คือเรื่องของ Index ที่ต้องดูว่าสร้างไว้ถูกต้อง เพียงพอ หรือว่าสร้างมากเกินจำเป็นหรือป่าว เนื่องจากว่าการสร้าง Index มากเกินไป ก็ทำให้เสีย performance ในการ insert update delete ข้อมูลใน database ได้นั่นเองครับ</p><p>ถึงตรงนี้ขอย้ำอีกทีว่าทั้งหมดทั้งมวลที่เล่ามา มาจากเนื้อหาปากต่อปาก บวกกับการเดาของผมล้วนๆ ซึ่งระบบจริงอาจจะไม่ได้เป็นอย่างนี้ก็ได้ แนะนำว่าอ่านเอาสนุก หรืออาจจะเก็บไปพิจารณาเป็นประสบการณ์ก็ได้ แต่อย่าได้ซีเรียสกับมันเลยนะครับ</p><p>ทีนี้เดากันมาเยอะละ ผมก็เลยลองออกแบบ Flow มาบ้างละกันว่าถ้าผมทำจะออกมาเป็นยังไง ซึ่งตรงนี้ เพื่อนๆสามารถติชมกันได้นะครับ ผมออกแบบมาแบบคร่าวๆอีกที ไม่แน่ใจว่าจะมีปัญหาตรงไหนตามมาอีกทีหลังจากเอาไปใช้งานจริงหรือป่าวครับ</p><p>โดย Flow ของผมจะแบ่งออกเป็น 2 ส่วน โดยส่วนแรกจะเป็นการ submit form เพื่อขอ code สำหรับนำไปกรอกเพื่อจอง ประมาณนี้</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QIqjff79tU3h7TwAKDrRtg.png" /></figure><p><strong>STEP 1</strong> — ลูกค้ากรอกข้อมูลส่วนตัว เลขบัตรประชาชนและ Email เข้าไปในระบบ</p><p><strong>STEP 2 </strong>— ตัวระบบเองจะทำการ Hash ข้อมูลบัตรประชาชนลูกค้า พร้อมทั้ง Generate Code ขึ้นมาชุดนึง แล้วเก็บลง Cache Storage ตรงนี้ผมเลือกเป็น Redis ละกัน (ที่เลือกเพราะใช้เป็นอยู่เจ้าเดียวครับ 55555) โดยให้ Hash ของเราเป็น Key และ Code เป็น Value ครับ ซึ่งตรงนี้จะมี Logic อยู่นิดนึง โดยการนำ Hash ของเราไปเช็คกับ Redis ก่อนว่ามีข้อมูลหรือยัง ถ้ามีแล้วก็แสดงว่าเคยจองไปแล้ว เราก็จะ็ตี Fail กลับไป</p><p><strong>STEP 3</strong> — เราเอาข้อมูลที่ได้รับมาจากลูกค้าส่งต่อไปให้ Message Queue ของเรา ตรงนี้ผมเลือกเป็น Kafka ละกัน (เนื่องจากเหตุผลเดียวกันกับข้างบนเลย) ตรงนี้ผมใช้ เวลาที่ลูกค้า request เข้ามา เอามาทำเป็น Partition Key แล้วให้ queue ของผมเป็นแบบ FIFO ซึ่งตรงนี้อาจจะทำงานช้าหน่อย แต่ไม่เป็นไร เราปล่อยมันทำไป เสร็จเมื่อไหร่ก็เมื่อนั้น</p><p><strong>STEP 4 — </strong>ตรงนี้จะมี Consumer คอยเอา Message จาก Kafka มา Process ต่อโดยอาจจะกำหนดกลุ่มของลูกค้าไปเลยว่าลูกค้าสามารถนำ Code ไปใช้ได้ในช่วงเวลาไหนบ้าง หรืออาจจะทำการแบ่ง Lot ในการส่ง Email ให้ลูกค้าใน STEP นี้ ยกตัวอย่าง อย่างเช่นว่า เราอยากให้ช่วง 11.00–12.00 ของวันถัดไป มีลูกค้าเข้ามาทำการจองได้สูงสุดพร้อมกันที่ 2,000 คนเราก็จะสามารถ control ได้ จากนั้นก็เก็บลง database และ cache storage ให้เรียบร้อย</p><p><strong>STEP 5</strong> — ตรงนี้ผม Design เผื่อไว้ว่าเราอาจจะมี Batch สำหรับ ส่ง email แยกเก็บไว้ หรืออาจจะทำเป็น cronjob อีกทีก็ได้เหมือนกัน เผื่อว่าบางที เราอาจจะยังไม่พร้อมส่ง Email ณ ตอนนั้น หรืออาจจะเกิดเหตุฉุกเฉินทำให้ยังไม่สามารถส่ง Email ให้ลูกค้าได้ แต่ถ้าพร้อมจะส่ง mail ให้ลูกค้าเมื่อไหร่ก็ค่อยสั่งให้ระบบทำงานอีกทีครับ</p><p>พอถึงตรงนี้ลูกค้าก็จะทยอยได้ Email กันบ้างแล้ว บางคนอาจจะได้ใช้ บางคนอาจจะได้เร็ว แต่ไม่ต้องมีใครมานั่งรอกดจอง แล้วนั่งเฝ้าหน้าจอระหว่างที่ระบบล่มทั้งวันแล้ว ซึ่งพอลูกค้าได้ Email ก็จะเข้าสู่ Flow ถัดไปครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T5NUWgsiv6kDGCVMWf_IzA.png" /></figure><p>พอลูกค้าได้รับ Email ใน Mail ของลูกค้าก็จะมี Code ซึ่งแยกไปตามแต่ละบุคคล โดยจะมี STEP ตามนี้ครับ</p><p><strong>STEP 1</strong> — ลูกค้านำ Code ที่ได้มากรอกในหน้าเว็บ พร้อมกับระบุเลขบัตรประชาชนของตัวเองจากนั้นก็กด Submit โลดดด</p><p><strong>STEP 2</strong> — ตัวระบบเองจะนำ เลขบัตรประชาชนที่ได้ไป Hash แล้ว Get ค่าจาก Redis ของเรา เพื่อนำค่าที่ได้มาเช็คว่า มีข้อมูลจริงมั้ย code ที่ส่งมาถูกหรือป่าว แล้วช่วงเวลาที่กดมา ตรงกับที่ระบบกำหนดไว้มั้ย ถ้าไม่ตรงก็ตี Fail กลับไปได้เลยตรงนี้ครับ แต่ถ้าตรงก็ให้ไปต่อ</p><p><strong>STEP 3 </strong>— ตรงนี้ก็ให้ลูกค้าเลือกรุ่น เลือกข้อมูลสาขา เลือกวันที่และเวลาที่จะรับได้เลย พอเสร็จแล้วก็กดส่ง แล้วเราค่อยไปเช็คว่าข้อมูลที่ลูกค้ากรอกมา สามารถใช้จองได้มั้ย ถ้าใช้ไม่ได้ ไม่ตรงเงื่อนไข ก็ตอบ Fail กลับไปเลย แต่ถ้าใช้ได้ก็เก็บลง database แล้วก็ส่ง Email แจ้งลูกค้าว่าเรียบร้อย เท่านี้เป็นอันจบ Flow ยิ้มได้เลย</p><p>แต่ทีนี้ Flow ที่ผมคิดออกมา อาจจะยังมีช่องโหว่อยู่ และอาจจะมีปัญหาเรื่องระยะเวลาในการทำ บวกกับงบประมาณที่ต้องใช้ก็ได้ เหมือนกัน และที่ยิ่งไปกว่านั้น อาจจะมีเงื่อนไขเบื้องหลังหรือมี Bussiness Logic ที่ผมยังไม่รู้อีกด้วยก็ได้ แต่เท่าที่ได้รับข้อมูลมา บวกกับการมโนของผมเอง ก็คิดว่า Flow นี้น่าจะใช้งานได้ในระดับนึงแหละ</p><p>ถึงตรงนี้ถ้าใครมีไอเดียดีๆ หรือมี Comment อยากติชม ก็สามารถเข้าไปทักหาผม หรืออาจจะไป Comment ในโพสได้เหมือนกันนะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dba4321492b5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาเขียน Golang กันเถอะ ตอนที่ 8]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-golang-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-8-3b5abc35757f?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/3b5abc35757f</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Tue, 17 Jun 2025 11:31:39 GMT</pubDate>
            <atom:updated>2025-06-17T11:31:39.028Z</atom:updated>
            <content:encoded><![CDATA[<p>ลองนึกภาพตามนะครับ ถ้าโปรแกรมของเราใหญ่และซับซ้อนขึ้นเรื่อยๆ func main() ของเราก็จะยาวเหยียดเป็นร้อยเป็นพันบรรทัดเหมือนเรียงความที่ไม่มีการย่อหน้าเลย มันจะอ่านยาก แก้ไขลำบาก และถ้ามีโค้ดส่วนไหนที่เราอยากใช้ซ้ำๆ ก็ต้องคัดลอกไปวางใหม่ทุกครั้ง ซึ่งไม่ใช่วิธีที่ดีเลยใช่มั้ยครับ แล้วจะแก้ปัญหายังไง ตอนนี้มีคำตอบครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hPGGzLe1W0Vh7UHuZRMrzQ.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้เราจะมาแก้ปัญหานี้กันด้วยการเรียนรู้เครื่องมือที่สำคัญที่สุดอย่างหนึ่งในการเขียนโปรแกรม นั่นคือการสร้าง <strong>ฟังก์ชัน (Functions)</strong> ครับ</p><h3>Function คืออะไร?</h3><p><strong>Function</strong> คือ <strong>“กล่องเครื่องมือ”</strong> หรือ <strong>“สูตรอาหาร”</strong> ที่เราสร้างขึ้นมาเก็บชุดคำสั่งไว้ แล้วตั้งชื่อให้มัน เพื่อให้เราสามารถเรียกใช้งานซ้ำๆ ได้ง่ายๆ ครับ</p><p>ลองนึกภาพฟังก์ชันเหมือน <strong>“เครื่องปั่นน้ำผลไม้”</strong></p><p><strong>1. Input (สิ่งที่เราใส่เข้าไป):</strong> คือ <strong>ผลไม้, น้ำแข็ง, โยเกิร์ต</strong> ที่เราใส่ลงไปในโถปั่น</p><ul><li>ในโลกโปรแกรมมิง เราเรียกสิ่งนี้ว่า <strong>พารามิเตอร์ (Parameter)</strong></li></ul><p><strong>2. Process (สิ่งที่เกิดขึ้น):</strong> คือการที่เครื่องปั่น <strong>หมุนปั่นส่วนผสมทั้งหมดให้เข้ากัน</strong> เราไม่จำเป็นต้องรู้ว่ามอเตอร์ทำงานยังไง รู้แค่ว่ามันทำงานของมัน</p><ul><li>ในโลกโปรแกรมมิง นี่คือ <strong>โค้ดที่อยู่ข้างในฟังก์ชัน</strong></li></ul><p><strong>3. Output (สิ่งที่เราได้ออกมา):</strong> คือ <strong>น้ำผลไม้ปั่น (Smoothie)</strong> ที่พร้อมดื่ม</p><ul><li>ในโลกโปรแกรมมิง เราเรียกสิ่งนี้ว่า <strong>ค่าที่ส่งคืน (Return Value)</strong></li></ul><p><strong>ข้อดีของ function โดยหลักๆ เลยก็คือ</strong></p><ul><li><strong>Reusability (ใช้ซ้ำได้):</strong> แทนที่จะเขียนโค้ดบวกลบคูณหารซ้ำๆ เราก็สร้างฟังก์ชัน calculate() ขึ้นมาอันเดียวแล้วเรียกใช้เมื่อไหร่ก็ได้</li><li><strong>Organization (จัดระเบียบ):</strong> ช่วยแบ่งโปรแกรมที่ซับซ้อนออกเป็นส่วนเล็กๆ ที่เข้าใจง่าย</li><li><strong>Readability (อ่านง่าย):</strong> ฟังก์ชันที่มีชื่อสื่อความหมาย (เช่น printReport()) จะช่วยให้คนอื่นเข้าใจได้ทันทีว่าโค้ดส่วนนั้นทำอะไร</li></ul><p><strong>หน้าตา function ก็จะเป็นประมาณนี้</strong></p><pre>func ชื่อฟังก์ชัน(พารามิเตอร์) (ชนิดข้อมูลที่ส่งคืน) {<br>    //<br>    // ส่วนของการทำงาน (Function Body)<br>    //<br>    return ค่าที่ส่งคืน<br>}</pre><p><strong>โครงสร้างของ function จะประกอบด้วย</strong></p><p><strong>1. คีย์เวิร์ด </strong><strong>func (The </strong><strong>func Keyword)<br></strong>คือ “คำสั่งเริ่มต้น” ที่บอก Go ว่า “สิ่งที่จะตามมานี้คือการนิยามฟังก์ชันนะ” ดังนั้นทุกครั้งที่จะสร้างฟังก์ชัน จะต้องขึ้นต้นด้วยคำว่า func เสมอ</p><p><strong>2. ชื่อฟังก์ชัน (Function Name)<br></strong>คือชื่อที่เราตั้งขึ้นเพื่อใช้อ้างอิงหรือเรียกใช้งานฟังก์ชันนี้ในภายหลัง</p><ul><li><strong>หลักการตั้งชื่อที่ดี:</strong> ควรเป็นชื่อที่สื่อความหมายว่าฟังก์ชันนั้นทำอะไร เช่น calculateTotalPrice, getUserFromDB, printReport</li><li>ใน Go นิยมใช้รูปแบบ <strong>camelCase</strong> ในการตั้งชื่อ (คำแรกขึ้นต้นด้วยตัวเล็ก คำถัดไปขึ้นต้นด้วยตัวใหญ่) เช่น calculateArea หรือถ้าต้องการนำไปใช้นอก Package ก็จะใช้รูปแบบ <strong>PascalCase </strong>ในการตั้งชื่อ (คำแรกขึ้นต้นด้วยตัวใหญ่ คำถัดไปขึ้นต้นด้วยตัวใหญ่) เช่น CreateProduct</li></ul><p><strong>3. พารามิเตอร์ (Parameter)</strong></p><p>คือ <strong>“ช่องรับข้อมูลเข้า” (Input)</strong> ของฟังก์ชัน เปรียบเสมือนวัตถุดิบที่เราจะส่งเข้าไปให้ฟังก์ชันทำงาน จะอยู่ภายในวงเล็บ ( ) ประกอบด้วย ชื่อพารามิเตอร์ ตามด้วย ชนิดข้อมูล</p><p>func add(parameterName int)</p><p>บางครั้งฟังก์ชันอาจจะ <strong>ไม่มีพารามิเตอร์เลยก็ได้</strong> ()</p><p>func add()</p><p>หรือถ้ามีหลายตัว ให้คั่นด้วยเครื่องหมาย , (comma)</p><p>func add(a int,b int)</p><p><strong>Trick:</strong> ถ้าพารามิเตอร์หลายตัวติดกันเป็นชนิดข้อมูลเดียวกัน สามารถรวบการประกาศชนิดข้อมูลไว้ท้ายสุดได้</p><pre>// แบบเต็ม<br>func add(a int, b int)<br><br>// แบบย่อ (นิยมใช้)<br>func add(a, b int)</pre><p><strong>4. Return Types </strong><strong>( ... )</strong></p><p>คือ ชนิดของข้อมูลที่เราต้องการ Return กลับออกไปเมื่อฟังก์ชันทำงานเสร็จแล้ว แต่ถ้าเราไม่ต้องการคืนค่าอะไรออกจาก function เราก็ไม่ต้องใส่ส่วนนี้เลย นอกจากนี้ถ้าเราต้องการ return ค่าออกไป ก็สามารถทำได้อีก 2 แบบนั่นคือ</p><ul><li><strong>คืนค่าเดียว:</strong> สามารถใส่แค่ชนิดข้อมูลได้เลย ไม่ต้องมีวงเล็บ เช่น int หรือ string</li><li><strong>คืนค่าหลายค่า:</strong> ต้องใส่วงเล็บครอบ และคั่นชนิดข้อมูลด้วย , เช่น (int, error) ซึ่งเป็นรูปแบบที่พบบ่อยมากใน Go สำหรับการคืนค่าผลลัพธ์พร้อมกับสถานะ error</li></ul><p><strong>5. Function Body </strong><strong>{ ... }<br></strong>คือส่วนที่อยู่ภายในวงเล็บปีกกา { } เป็นส่วนที่เก็บ <strong>“ชุดคำสั่ง” หรือ “ขั้นตอนการทำงาน”</strong> ทั้งหมดของฟังก์ชัน ถ้าฟังก์ชันมีการกำหนดว่าจะต้องคืนค่า (Return Types) ภายใน Body จะต้องมีคำสั่ง return เพื่อส่งค่ากลับไปให้ตรงตามชนิดที่กำหนดไว้</p><p>มาดูตัวอย่างฟังก์ชันที่ใช้งานจริงเพื่อเทียบกับโครงสร้างกันครับ</p><p><strong>ตัวอย่างที่ 1</strong>: ฟังก์ชันที่ไม่มีการรับค่าและคืนค่า</p><pre>package main<br>import &quot;fmt&quot;<br><br>// สร้างฟังก์ชันชื่อ sayHello<br>func sayHello() {<br>    fmt.Println(&quot;สวัสดี! ยินดีต้อนรับสู่โลกของ Go Functions&quot;)<br>}<br><br>func main() {<br>    // เรียกใช้งานฟังก์ชัน<br>    sayHello()<br>}</pre><p><strong>ตัวอย่างที่ 2</strong>: ฟังก์ชันที่รับค่า (Parameters) และคืนค่า (Return Value)</p><pre>package main<br>import &quot;fmt&quot;<br><br>// ฟังก์ชัน add รับค่า a และ b (ชนิด int)<br>// และคืนค่าผลรวมเป็นชนิด int<br>func add(a int, b int) int {<br>    result := a + b<br>    return result<br>}<br><br>// ถ้าพารามิเตอร์เป็นชนิดเดียวกัน สามารถเขียนย่อได้<br>func subtract(a, b int) int {<br>    return a - b<br>}<br><br>func main() {<br>    sum := add(10, 5)<br>    fmt.Println(&quot;ผลบวกคือ:&quot;, sum) // ผลลัพธ์: 15<br><br>    difference := subtract(10, 5)<br>    fmt.Println(&quot;ผลต่างคือ:&quot;, difference) // ผลลัพธ์: 5<br>}</pre><p><strong>ตัวอย่างที่ 3</strong>: ฟังก์ชันที่รับค่า (Parameters) และคืนค่าหลายค่า</p><pre>package main<br><br>import (<br> &quot;fmt&quot;<br> &quot;errors&quot;<br>)<br><br>// ฟังก์ชันหารเลข ที่คืนค่า 2 อย่าง:<br>// 1. ผลหาร (float64)<br>// 2. ข้อผิดพลาด (error)<br>func divide(a, b float64) (float64, error) {<br>    if b == 0 {<br>        // ถ้าตัวหารเป็น 0, ให้คืนค่า 0 และ error message<br>        return 0, errors.New(&quot;ไม่สามารถหารด้วยศูนย์ได้&quot;)<br>    }<br>    // ถ้าสำเร็จ, ให้คืนค่าผลลัพธ์ และ error เป็น nil (ไม่มีข้อผิดพลาด)<br>    return a / b, nil<br>}<br><br>func main() {<br>    // กรณีสำเร็จ<br>    result, err := divide(10.0, 2.0)<br>    if err != nil {<br>        fmt.Println(&quot;เกิดข้อผิดพลาด:&quot;, err)<br>    } else {<br>        fmt.Println(&quot;ผลหารคือ:&quot;, result) // ผลลัพธ์: 5<br>    }<br><br>    // กรณีเกิดข้อผิดพลาด<br>    result, err = divide(10.0, 0)<br>    if err != nil {<br>        fmt.Println(&quot;เกิดข้อผิดพลาด:&quot;, err) // ผลลัพธ์: เกิดข้อผิดพลาด: ไม่สามารถหารด้วยศูนย์ได้<br>    } else {<br>        fmt.Println(&quot;ผลหารคือ:&quot;, result)<br>    }<br>}</pre><h4>Method คืออะไร?</h4><p>Method คือฟังก์ชันที่ “ผูกติด” อยู่กับ type ที่เราสร้างขึ้น (ส่วนใหญ่คือ struct) มันทำให้เราสามารถเรียกใช้ฟังก์ชันจากตัวแปรของ Type นั้นได้โดยตรง และถูกเรียกอีกชื่อว่า Reciever function หรือจะเรียกว่า Reciever method ก็ได้เหมือนกัน แล้วแต่ที่ว่าจะเรียกแบบไหน</p><p><strong>ความแตกต่างระหว่าง Function ปกติ และ Method</strong></p><ul><li><strong>Function เราสามารถเรียกใช้งานได้เลย</strong></li><li><strong>Method:</strong> จำเป็นจะต้องสร้าง instance ของ struct ก่อนถึงจะเรียก method ผ่าน instance ได้อีกที</li></ul><p>ทีนี้เรามาลองสร้าง Method ให้กับ struct ที่เราคุ้นเคยกัน</p><pre>package main<br>import &quot;fmt&quot;<br><br>// 1. นิยาม Struct<br>type Rectangle struct {<br>    Width  float64<br>    Height float64<br>}<br><br>// 2. สร้าง Method ชื่อ area() สำหรับ Rectangle<br>// (r Rectangle) คือส่วนที่เรียกว่า &quot;Receiver&quot;<br>// มันทำให้โค้ดในฟังก์ชันนี้สามารถเข้าถึงฟิลด์ของ r (เช่น r.Width) ได้<br>func (r Rectangle) Area() float64 {<br>    return r.Width * r.Height<br>}<br><br>func main() {<br>    // 3. สร้าง Instance ของ Rectangle<br>    rect := Rectangle{Width: 10, Height: 5}<br><br>    // 4. เรียกใช้งาน Method ผ่านตัวแปร rect ได้เลย<br>    fmt.Printf(&quot;สี่เหลี่ยมผืนผ้าขนาด %.fx%.f\n&quot;, rect.Width, rect.Height)<br>    fmt.Println(&quot;มีพื้นที่เท่ากับ:&quot;, rect.Area()) // ผลลัพธ์: 50<br>}</pre><p>สรุปเลยในตอนนี้ เราได้ยกระดับการเขียนโค้ดไปอีกขั้นแล้ว เราสามารถสร้าง <strong>Function</strong> เพื่อห่อหุ้มโค้ดที่ทำงานเฉพาะทาง ทำให้ main ของเราสั้น สะอาด และยังสามารถสร้าง <strong>Method</strong> ให้กับ struct ที่เราออกแบบเองได้อีกด้วย ในตอนต่อไป เราจะมาทำความรู้จักกับหนึ่งในแนวคิดที่ทรงพลังที่สุดใน Go นั่นคือ <strong>Interfaces </strong>ถ้าอยากรู้ว่ามันคืออะไร เอาไปใช้ทำอะไรก็อย่าลืมติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage</strong></a> ของผมเอาไว้ด้วยนะครับ</p><p>สำหรับใครที่ติดปัญหา หรือมีข้อสงสัยเกี่ยวกับการเขียน <strong>Go</strong> ก็สามารถทักไปหาผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a><strong> </strong>ได้นะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3b5abc35757f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาเขียน Golang กันเถอะ ตอนที่ 7]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-golang-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-7-3a37ef4cc082?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a37ef4cc082</guid>
            <category><![CDATA[mos-programmer]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Sat, 14 Jun 2025 04:27:12 GMT</pubDate>
            <atom:updated>2025-06-14T04:27:12.019Z</atom:updated>
            <content:encoded><![CDATA[<p>ในบทเรียนที่ผ่านมา เราได้เรียนรู้วิธีใช้ Slice เพื่อเก็บข้อมูล “ชนิดเดียวกัน” หลายๆ ตัวไว้ด้วยกัน แต่ถ้าเราอยากจะเก็บข้อมูลของ “สิ่งของ” หนึ่งชิ้น ที่มีคุณสมบัติหลากหลายประเภทล่ะ? เช่น ข้อมูล “ผู้ใช้” หนึ่งคน ซึ่งประกอบไปด้วย ชื่อ (string), อายุ (int), และ สถานะการใช้งาน (bool) และอีกคำถามหนึ่งคือ ถ้าเรามีข้อมูลจำนวนมาก แล้วอยากจะค้นหาข้อมูลส่ิงของชิ้นหนึ่งอย่างรวดเร็วด้วย Keyword จะทำได้อย่างไร?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vTHeahlnZsJ1gdaVXwK7gw.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้ เราจะมาไขคำตอบของสองคำถามนี้ด้วย <strong>Structs</strong> และ <strong>Maps</strong> ซึ่งเป็นโครงสร้างข้อมูลที่สำคัญมากๆ ใน Go ครับ</p><h4>Struct คืออะไร?</h4><p><strong>Struct</strong> (อ่านว่า <em>สตรัค</em> หรือเต็มๆก็คือ <em>สตรัคเจอร์</em>) คือ <strong>“แม่แบบ” หรือ “พิมพ์เขียว”</strong> ที่เราสร้างขึ้นเองสำหรับเก็บข้อมูลหลายๆ อย่างที่เกี่ยวข้องกันไว้ในที่เดียวกัน</p><p>ลองนึกถึง <strong>“บัตรประชาชน”</strong> เป็นตัวอย่างที่ดีที่สุดครับ บนบัตรประชาชนใบหนึ่งไม่ได้มีแค่ข้อมูลเดียว แต่ประกอบไปด้วยข้อมูลหลายส่วน เช่น</p><ul><li><strong>ชื่อ-นามสกุล</strong> (เป็นข้อมูลชนิด ข้อความ)</li><li><strong>เลขประจำตัว</strong> (เป็นข้อมูลชนิด ข้อความ หรือ ตัวเลข)</li><li><strong>วันเกิด</strong> (เป็นข้อมูลชนิด วันที่)</li><li><strong>ที่อยู่</strong> (เป็นข้อมูลชนิด ข้อความ)</li></ul><p>ถ้าไม่มี “บัตรประชาชน” เราจะต้องถือข้อมูลเหล่านี้แยกกันเป็นชิ้นๆ ซึ่งมันคงจะวุ่นวายมากเลยทีเดียวครับ</p><p>วิธีประกาศและใช้งาน Struct เรา ให้เราใช้คีย์เวิร์ด type ตามด้วยชื่อ Struct และ struct เพื่อสร้างแม่แบบของเรา แบบนี้ครับ</p><pre>package main<br><br>import &quot;fmt&quot;<br><br>// 1. สร้าง แม่แบบ ของข้อมูลสินค้า โดยใช้ struct<br>// เรากำลังสร้าง Type ใหม่ที่ชื่อว่า Product<br>type Product struct {<br>    ID    string<br>    Name  string<br>    Price float64<br>    Stock int<br>}<br><br>func main() {<br>    // 2. สร้างข้อมูลสินค้าขึ้นมาจาก แม่แบบ ของเรา<br>    // เราเรียกสิ่งนี้ว่า &quot;Instance&quot; ของ Struct<br>    product1 := Product{<br>        ID:    &quot;P001&quot;,<br>        Name:  &quot;Laptop Pro 15&quot;,<br>        Price: 55900.50,<br>        Stock: 25,<br>    }<br><br>    product2 := Product{<br>        ID:    &quot;P002&quot;,<br>        Name:  &quot;Wireless Mouse&quot;,<br>        Price: 899.00,<br>        Stock: 150,<br>    }<br><br>    // 3. การเข้าถึงข้อมูลแต่ละฟิลด์ (Field) ทำได้โดยใช้เครื่องหมายจุด (.)<br>    fmt.Println(&quot;ข้อมูลสินค้าชิ้นแรก:&quot;)<br>    fmt.Printf(&quot;  ชื่อ: %s\n&quot;, product1.Name)<br>    fmt.Printf(&quot;  ราคา: %.2f บาท\n&quot;, product1.Price)<br><br>    fmt.Println(&quot;\nข้อมูลสินค้าชิ้นที่สอง:&quot;)<br>    fmt.Printf(&quot;  รหัส: %s\n&quot;, product2.ID)<br>    fmt.Printf(&quot;  จำนวนในสต็อก: %d ชิ้น\n&quot;, product2.Stock)<br>}</pre><h4>Struct ใช้แก้ปัญหาอะไรในเคสนี้ ?</h4><p>ลองจินตนาการว่าเราจะเก็บข้อมูลของหนังสือ 1 เล่ม ถ้าไม่มี Struct เราอาจต้องทำแบบนี้</p><pre>var bookTitle1 string = &quot;Harry Potter&quot;<br>var bookAuthor1 string = &quot;J.K. Rowling&quot;<br>var bookPages1 int = 400</pre><p>ถ้ามีหนังสือ 100 เล่มล่ะ? เราก็ต้องสร้างตัวแปรแบบนี้อีก 300 ชุด ซึ่งจัดการได้ยากมาก แต่ถ้าเราใช้ Struct เราสามารถสร้าง <strong>“แม่แบบ”</strong> ของหนังสือขึ้นมาก่อน แบบนี้ได้</p><pre>// 1. สร้างแม่แบบ ที่ชื่อว่า Book<br>type Book struct {<br>    Title  string<br>    Author string<br>    Pages  int<br>}</pre><p>จากนั้น เวลาเราจะสร้างข้อมูลหนังสือเล่มใหม่ ก็แค่นำ แม่แบบ น้ีไปใช้ แบบนี้ครับ</p><pre>// 2. สร้างหนังสือเล่มจริงจากแม่แบบ<br>book1 := Book{<br>    Title:  &quot;Harry Potter&quot;,<br>    Author: &quot;J.K. Rowling&quot;,<br>    Pages:  400,<br>}<br><br>book2 := Book{<br>    Title: &quot;The Lord of the Rings&quot;,<br>    Author: &quot;J.R.R. Tolkien&quot;,<br>    Pages: 1178,<br>}<br><br>// 3. การเข้าถึงข้อมูลก็ง่ายและอ่านรู้เรื่อง<br>fmt.Println(book1.Title) // แสดงผล: Harry Potter<br>fmt.Println(book2.Author) // แสดงผล: J.R.R. Tolkien</pre><p>เท่านี้เราก็จะสามารถจัดการข้อมูลของเราได้แล้ว</p><h4><strong>Map</strong> คืออะไร?</h4><p>Map คือชุดข้อมูลที่เก็บข้อมูลเป็นคู่ๆ แบบ <strong>“Key-Value” </strong>ซึ่งเราใช้ “Key” เพื่อค้นหา “Value” ที่คู่กันได้อย่างรวดเร็ว</p><p>เปรียบเทียบให้เห็นภาพที่สุด ลองนึกถึง <strong>“พจนานุกรม”</strong> สักเล่มนึง <strong>พจนานุกรมทั้งเล่ม</strong> เปรียบเสมือนข้อมูล type <strong>Map</strong> ของเรา ส่วน <strong>คำศัพท์</strong> ที่เราเปิดหา (เช่น “Cat”) คือ <strong>Key </strong>และ <strong>ความหมาย</strong> ของคำศัพท์นั้น (เช่น “แมว, สัตว์เลี้ยงลูกด้วยนม”) ก็คือ <strong>Value </strong>นั่นเองครับ</p><p>เราสามารถประกาศตัวแปร type Map ได้ โดยใช้คีย์เวิร์ด map[KeyType]ValueType แบบนี้ครับ</p><pre>package main<br><br>import &quot;fmt&quot;<br><br>func main() {<br>    // สร้าง Map โดยใช้ make<br>    // Key เป็น string และ Value เป็น int (เช่น ชื่อวิชา และ คะแนน)<br>    scores := make(map[string]int)<br><br>    // การเพิ่มหรือแก้ไขข้อมูล<br>    scores[&quot;Math&quot;] = 95<br>    scores[&quot;Science&quot;] = 88<br>    scores[&quot;History&quot;] = 76<br><br>    fmt.Println(&quot;คะแนนทั้งหมด:&quot;, scores) // ผลลัพธ์: map[History:76 Math:95 Science:88]<br><br>    // การดึงข้อมูล<br>    mathScore := scores[&quot;Math&quot;]<br>    fmt.Println(&quot;คะแนนวิชาคณิตศาสตร์:&quot;, mathScore)<br><br>    // การลบข้อมูล<br>    delete(scores, &quot;History&quot;)<br>    fmt.Println(&quot;คะแนนหลังลบวิชาประวัติศาสตร์:&quot;, scores)<br><br>    // การสร้าง Map พร้อมกำหนดค่าเริ่มต้น<br>    capitals := map[string]string{<br>        &quot;Thailand&quot;: &quot;Bangkok&quot;,<br>        &quot;Japan&quot;:    &quot;Tokyo&quot;,<br>        &quot;USA&quot;:      &quot;Washington, D.C.&quot;,<br>    }<br>    fmt.Println(&quot;เมืองหลวงของญี่ปุ่นคือ:&quot;, capitals[&quot;Japan&quot;])<br>}</pre><p>แต่การใช้ Map นั้นมีข้อควรระวังอยู่อย่างนึงครับ ถ้าเราค้นหา Key ที่ไม่มีอยู่ ค่าที่ได้จะเป็นค่าว่าง (Zero Value) ของ Value Type นั้นๆ (เช่น 0 สำหรับ int, “” สำหรับ string) ซึ่งอาจทำให้เราสับสนได้ว่า “Key ไม่มีอยู่จริง” หรือ “Key มีอยู่แต่ค่าของมันคือ 0”</p><p>Go จึงมีวิธีตรวจสอบที่ค่อนข้างนิยม เรียกว่า <strong>“comma ok” </strong>ครับ หน้าตาก็จะเป็นแบบนี้</p><pre>// ... ต่อจากโค้ด Map ด้านบน ...<br>// ลองค้นหาคะแนนวิชาศิลปะ (Art) ซึ่งไม่มีอยู่<br>artScore, ok := scores[&quot;Art&quot;]<br>if ok {<br>    // ถ้า ok เป็น true แสดงว่ามี Key นี้อยู่จริง<br>    fmt.Println(&quot;คะแนนวิชาศิลปะคือ:&quot;, artScore)<br>} else {<br>    // ถ้า ok เป็น false แสดงว่าไม่มี Key นี้ใน Map<br>    fmt.Println(&quot;ไม่พบข้อมูลคะแนนวิชาศิลปะ&quot;)<br>}</pre><p>ทีนี้เราลองเอา Struct และ Map มารวมกันดู โดยผมจะทำเป็นตัวอย่าง จัดการคลังสินค้าด้วย Struct และ Map ก็แล้วกันนะครับ code ก็จะมีรายละเอียดตามนี้</p><ul><li>ใช้ <strong>Struct</strong> เพื่อเป็นแม่แบบของข้อมูลสินค้า</li><li>ใช้ <strong>Map</strong> เพื่อเป็นคลังสินค้า โดยใช้ “รหัสสินค้า” (ID) เป็น Key และใช้ “ข้อมูลสินค้า” (Product Struct) เป็น Value</li></ul><p><strong>ตัวอย่าง Code</strong></p><pre>package main<br><br>import &quot;fmt&quot;<br><br>// แม่แบบข้อมูลสินค้า (เหมือนเดิม)<br>type Product struct {<br>    Name  string<br>    Price float64<br>}<br><br>func main() {<br>    // สร้างคลังสินค้า (Map) ที่เก็บ Product<br>    // Key คือ รหัสสินค้า (string), Value คือ Product<br>    inventory := make(map[string]Product)<br><br>    // เพิ่มสินค้าเข้าคลัง<br>    inventory[&quot;P001&quot;] = Product{Name: &quot;Gaming Keyboard&quot;, Price: 2500.0}<br>    inventory[&quot;P002&quot;] = Product{Name: &quot;27-inch Monitor&quot;, Price: 7800.0}<br><br>    // ค้นหาสินค้าด้วยรหัส &quot;P002&quot;<br>    fmt.Println(&quot;--- ค้นหาสินค้า P002 ---&quot;)<br>    product, ok := inventory[&quot;P002&quot;]<br>    if ok {<br>        fmt.Printf(&quot;พบสินค้า: %s, ราคา: %.2f บาท\n&quot;, product.Name, product.Price)<br>    } else {<br>        fmt.Println(&quot;ไม่พบสินค้า P002&quot;)<br>    }<br><br>    // วนลูปดูสินค้าทั้งหมดในคลัง<br>    fmt.Println(&quot;\n--- สินค้าทั้งหมดในคลัง ---&quot;)<br>    for id, prod := range inventory {<br>        fmt.Printf(&quot;รหัส: %s -&gt; สินค้า: %s, ราคา: %.2f บาท\n&quot;, id, prod.Name, prod.Price)<br>    }<br>}</pre><p>ถึงตรงนี้เราได้เรียนรู้วิธีการใช้งาน Struct และ Map กันไปแล้ว แต่โค้ดของเรายังอยู่รวมกันใน func main() ทั้งหมด ในตอนต่อไป เราจะมาเรียนรู้วิธีการจัดระเบียบ &quot;พฤติกรรม&quot; ของโปรแกรม โดยการสร้าง <strong>&quot;ฟังก์ชัน (Functions)&quot;</strong> ของเราเอง เพื่อให้โค้ดสะอาด อ่านง่าย และนำกลับมาใช้ใหม่ได้ครับ</p><p>สำหรับใครที่ติดปัญหา หรือมีข้อสงสัยเกี่ยวกับการเขียน <strong>Go</strong> ก็สามารถทักไปหาผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a><strong> </strong>ได้นะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a37ef4cc082" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[หัดเขียนโปรแกรมกับเจ้าหลามน้อย Python ตอนที่ 10]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-10-4827136c25b6?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/4827136c25b6</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Sat, 14 Jun 2025 01:02:39 GMT</pubDate>
            <atom:updated>2025-06-14T01:02:39.824Z</atom:updated>
            <content:encoded><![CDATA[<p>ยินดีด้วยครับ! คุณเดินทางมาถึงตอนสุดท้ายของบทความชุด “หัดเขียนโปรแกรมกับเจ้าหลามน้อย Python” แล้วนะครับ ถือว่าคุณได้สร้างรากฐานที่แข็งแกร่งในการเขียนโปรแกรมด้วย Python แล้วล่ะครับ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9k5XY7Wn03bGLe8wYGM48Q.jpeg" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="https://www.facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ บทความนี้ก็จะเป็นการสรุปสุดท้ายของบทความชุด “หัดเขียนโปรแกรมกับเจ้าหลามน้อย Python” แล้วนะครับ</p><h3>สรุปสิ่งที่คุณได้เรียนรู้มา</h3><p>ตลอดบทเรียนที่ผ่านมา เราได้ปูพื้นฐานสำคัญของ Python ตั้งแต่เริ่มต้นเลยนะครับ ลองมาทบทวนกันหน่อยว่าเราได้เรียนรู้อะไรไปบ้าง:</p><p><a href="https://medium.com/@mosprogrammer/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-0-8797f816981b"><strong>ตอนที่ 0</strong></a></p><ul><li><strong>เราได้ทำการการติดตั้ง Python</strong> และ <strong>VS Code</strong> ซึ่งเป็นเครื่องมือคู่ใจของเรา</li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-1-829c665bb0ad"><strong>ตอนที่ 1</strong></a></p><ul><li>เราได้ทำความรู้จักว่า Python คืออะไร?</li><li>เราได้รู้จัก Syntax ต่างๆ และ Type ของตัวแปรใน Python</li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-2-fbface7eae68"><strong>ตอนที่ 2</strong></a></p><ul><li>เรียนรู้เรื่อง Datetime และ String</li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-3-5703b9eb741a"><strong>ตอนที่ 3</strong></a></p><ul><li>เราได้เรียนรู้เรื่อง คำสั่งเงื่อนไข IF , IF … Else และ เครื่องหมาย ตรรกศาสตร์ต่างๆ</li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-4-92eff11dd168"><strong>ตอนที่ 4</strong></a></p><ul><li>รู้จักกับ Loop</li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-5-eba047e74edc"><strong>ตอนที่ 5</strong></a></p><ul><li>เรียนรู้กับสิ่งที่เรียกว่า <strong>ฟังก์ชัน (Functions)</strong></li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-6-47636aa895d2"><strong>ตอนที่ 6</strong></a></p><ul><li>ได้รู้จักกับ <strong>โครงสร้างข้อมูล (Data Structures)</strong></li></ul><p><a href="https://mosprogrammer.medium.com/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-7-bbb06a50e5f2"><strong>ตอนที่ 7</strong></a></p><ul><li><strong>รับมือกับข้อผิดพลาด (handle errors)</strong></li></ul><p><a href="https://medium.com/@mosprogrammer/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-8-1d9c9fa8bf56"><strong>ตอนที่ 8</strong></a></p><ul><li>รู้จักการนำเข้าโค้ดจาก <strong>โมดูล</strong> หรือ <strong>แพ็กเกจ</strong> อื่น ๆ</li></ul><p><a href="https://medium.com/@mosprogrammer/%E0%B8%AB%E0%B8%B1%E0%B8%94%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%82%E0%B8%9B%E0%B8%A3%E0%B9%81%E0%B8%81%E0%B8%A3%E0%B8%A1%E0%B8%81%E0%B8%B1%E0%B8%9A%E0%B9%80%E0%B8%88%E0%B9%89%E0%B8%B2%E0%B8%AB%E0%B8%A5%E0%B8%B2%E0%B8%A1%E0%B8%99%E0%B9%89%E0%B8%AD%E0%B8%A2-python-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-9-33db28d09955"><strong>ตอนที่ 9</strong></a></p><ul><li><strong>“การจัดการไฟล์” (File Handling)</strong></li></ul><p>นี่คือหัวใจหลักของ Python ที่จะทำให้คุณสามารถเขียนโปรแกรมพื้นฐานต่าง ๆ ได้อย่างมั่นใจครับ</p><h3>การเดินทางต่อไปในโลก Python</h3><p>การเรียนรู้โปรแกรมมิ่งเป็นกระบวนการที่ไม่สิ้นสุดครับ ยิ่งคุณฝึกฝนและเรียนรู้มากขึ้นเท่าไหร่ คุณก็จะยิ่งเก่งขึ้นเท่านั้น นี่คือแนวทางที่คุณสามารถเรียนรู้ Python ต่อไปได้ครับ:</p><ol><li><strong>ลงมือเขียนโค้ดเยอะ ๆ:</strong> “รู้” กับ “ทำได้” ไม่เหมือนกันครับ วิธีที่ดีที่สุดคือการลงมือเขียนโค้ดจริง ๆ ลองทำโจทย์ง่าย ๆ ในอินเทอร์เน็ต หรือลองสร้างโปรแกรมเล็ก ๆ ที่คุณสนใจ</li><li><strong>เรียนรู้โครงสร้างข้อมูลเพิ่มเติม:</strong> Python ยังมีโครงสร้างข้อมูลอื่น ๆ ที่น่าสนใจ เช่น <strong>Dictionary (พจนานุกรม)</strong> และ <strong>Set (เซ็ต)</strong> ซึ่งมีประโยชน์มากในการจัดการข้อมูลประเภทต่าง ๆ ครับ</li><li><strong>เรียนรู้เรื่อง “การเขียนโปรแกรมเชิงวัตถุ” (Object-Oriented Programming — OOP):</strong> นี่คือแนวคิดการเขียนโปรแกรมที่สำคัญมาก ๆ และใช้กันอย่างแพร่หลาย Python เป็นภาษาที่รองรับ OOP ได้ดีครับ</li><li><strong>ศึกษาไลบรารีและเฟรมเวิร์กยอดนิยม:</strong></li></ol><ul><li><strong>Data Science / Machine Learning:</strong> ถ้าสนใจสายข้อมูล ลองดู <strong>NumPy</strong>, <strong>Pandas</strong>, <strong>Matplotlib</strong>, <strong>Scikit-learn</strong>, <strong>TensorFlow</strong>, <strong>PyTorch</strong></li><li><strong>Web Development:</strong> ถ้าอยากทำเว็บไซต์ ลองดู <strong>Django</strong> หรือ <strong>Flask</strong></li><li><strong>Automation / Scripting:</strong> คุณจะพบว่า Python มีไลบรารีมากมายที่ช่วยทำงานอัตโนมัติได้เกือบทุกอย่างครับ</li><li><strong>Game Development:</strong> <strong>Pygame</strong> ก็เป็นตัวเลือกที่ดีสำหรับการเริ่มต้นครับ</li></ul><p><strong>5. เข้าร่วม Community:</strong> ค้นหากลุ่มคนรัก Python ทั้งบน Facebook, Discord, Stack Overflow หรือ Reddit ครับ การได้พูดคุย ถามคำถาม และช่วยเหลือผู้อื่น จะช่วยให้คุณพัฒนาเร็วขึ้นมาก</p><p><strong>6. อ่านเอกสาร (Documentation):</strong> เอกสารทางการของ Python และของไลบรารีต่าง ๆ เป็นแหล่งข้อมูลที่ดีที่สุดครับ ลองฝึกอ่านและทำความเข้าใจดู</p><p>สุดท้ายนี้ ผมขอแสดงความยินดีกับคุณอีกครั้งนะครับที่ก้าวเข้ามาในโลกของ Python และอดทนเรียนรู้มาจนถึงตรงนี้ การเรียนรู้การเขียนโค้ดเป็นทักษะที่มีค่ามากในยุคปัจจุบัน และผมหวังว่าบทความนี้จะเป็นก้าวแรกที่มั่นคงในการเดินทางของคุณครับ</p><p>ขอขอบคุณทุกคนที่คอยติดตามบทความชุดนี้ มากๆเลยนะครับ ขอบคุณทุกการกด Like และ กด Share บทความของผม ถือว่าเป็นกำลังใจที่ดี ให้ผมได้ทำบทความมาจนถึงตอนนี้ได้</p><p>แล้วก็ยังไง ฝากกดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> เพื่อที่เราจะได้ออกเดินทางไปกับเนื้อหาความรู้ใหม่ๆด้วยกัน สำหรับบทความชุดนี้ก็มีเพียงเท่านี้ แล้วเจอกันใหม่กับบทความชุดถัดไปครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4827136c25b6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[มาเขียน Golang กันเถอะ ตอนที่ 6]]></title>
            <link>https://mosprogrammer.medium.com/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-golang-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-%E0%B8%95%E0%B8%AD%E0%B8%99%E0%B8%97%E0%B8%B5%E0%B9%88-6-030426ae9ce3?source=rss-9339287ae40d------2</link>
            <guid isPermaLink="false">https://medium.com/p/030426ae9ce3</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[mos-programmer]]></category>
            <dc:creator><![CDATA[Mos Programmer]]></dc:creator>
            <pubDate>Thu, 12 Jun 2025 16:26:16 GMT</pubDate>
            <atom:updated>2025-06-12T16:26:16.657Z</atom:updated>
            <content:encoded><![CDATA[<p>ในบทเรียนที่ผ่านมา เราได้เรียนรู้การทำงานกับข้อมูลทีละตัว การควบคุมโปรแกรม และการวนซ้ำไปแล้ว แต่ในโลกแห่งความเป็นจริง บ่อยครั้งเราต้องทำงานกับข้อมูลที่เป็นกลุ่มก้อน เช่น รายชื่อนักเรียนในห้อง, รายการสินค้าในตะกร้า, หรือคะแนนสอบของแต่ละวิชา</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TXyX2Yae8ks4m2n28HLZGA.png" /></figure><p>สวัสดีครับ ผมมอส เจ้าของ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> ครับ ในบทความนี้ เราจะมาเรียนรู้โครงสร้างข้อมูลพื้นฐาน 2 ชนิดที่ใช้สำหรับจัดการข้อมูลเป็นชุดใน Go นั่นคือ <strong>Arrays</strong> และ <strong>Slices</strong> กันครับ</p><h4>1. อาร์เรย์ (Array)</h4><p>ลองนึกภาพ Array เหมือน “แผงไข่ไก่” ครับ มันถูกสร้างมาให้มีจำนวนช่องที่แน่นอน (เช่น 12 ช่อง) เราไม่สามารถยัดไข่ฟองที่ 13 เข้าไปได้ และไม่สามารถทำให้แผงเล็กลงเหลือ 10 ช่องได้</p><p><strong>คุณสมบัติหลักของ Array:</strong></p><ul><li><strong>ขนาดคงที่ (Fixed-size):</strong> ขนาดของ Array จะถูกกำหนดตั้งแต่ตอนสร้างและไม่สามารถเปลี่ยนแปลงได้</li><li><strong>เก็บข้อมูลชนิดเดียวกัน (Homogeneous):</strong> สมาชิกทุกตัวใน Array ต้องเป็นข้อมูลชนิดเดียวกัน</li></ul><p><strong>การประกาศและใช้งาน Array<br></strong>เราประกาศ Array โดยระบุขนาดไว้ในวงเล็บ []</p><pre>package main<br><br>import &quot;fmt&quot;<br><br>func main() {<br>    // ประกาศ Array ชื่อ &#39;scores&#39; เพื่อเก็บข้อมูลชนิด int จำนวน 3 ช่อง<br>    // ทุกช่องจะถูกกำหนดค่าเริ่มต้นเป็น 0 (Zero Value ของ int)<br>    var scores [3]int<br>    fmt.Println(&quot;Array เริ่มต้น:&quot;, scores) // ผลลัพธ์: [0 0 0]<br><br>    // กำหนดค่าให้สมาชิกแต่ละช่อง (Index เริ่มนับที่ 0)<br>    scores[0] = 85<br>    scores[1] = 92<br>    scores[2] = 78<br>    fmt.Println(&quot;หลังกำหนดค่า:&quot;, scores)       // ผลลัพธ์: [85 92 78]<br>    fmt.Println(&quot;คะแนนตัวแรก:&quot;, scores[0]) // ผลลัพธ์: 85<br><br>    // การประกาศพร้อมกำหนดค่าทันที<br>    // เราสามารถใช้ ... เพื่อให้ Go นับขนาดให้เองได้<br>    weekdays := [...]string{&quot;จันทร์&quot;, &quot;อังคาร&quot;, &quot;พุธ&quot;, &quot;พฤหัสบดี&quot;, &quot;ศุกร์&quot;}<br>    fmt.Println(&quot;จำนวนวันทำงาน:&quot;, len(weekdays)) // len() ใช้หาความยาว<br>}</pre><p><strong>สรุปสำหรับ Array:</strong> มีประโยชน์เมื่อคุณรู้จำนวนข้อมูลที่แน่นอนและมั่นใจว่าจะไม่เปลี่ยนแปลง แต่ในการใช้งานส่วนใหญ่ใน Go เรามักจะหันไปใช้สิ่งที่ยืดหยุ่นกว่า นั่นคือ “Slice”</p><h4>2. สไลซ์ (Slice)</h4><p>ถ้า Array คือแผงไข่ Slice ก็เหมือน “ตะกร้าช็อปปิ้ง” ที่เราสามารถใส่ของเข้าไปได้เรื่อยๆ ตะกร้าสามารถขยายขนาดเพื่อรองรับของที่เพิ่มขึ้นได้ นี่คือโครงสร้างข้อมูลที่คุณจะได้ใช้บ่อยที่สุดใน <strong>Go</strong></p><p><strong>Slice คือ “ส่วนแสดงผล” ของ Array ที่ซ่อนอยู่เบื้องหลัง</strong> แต่มีกลไกที่ทำให้มันยืดหยุ่นและทรงพลังกว่ามาก</p><p><strong>คุณสมบัติหลักของ Slice:</strong></p><ul><li><strong>ขนาดยืดหยุ่น (Dynamic-size):</strong> สามารถเพิ่ม (หรือลด) สมาชิกได้ตามต้องการ</li><li><strong>เป็นที่นิยมใช้งานสูง:</strong> เป็นวิธีมาตรฐานในการจัดการข้อมูลเป็นลำดับใน Go</li></ul><p><strong>การประกาศและใช้งาน Slice<br></strong>การประกาศ Slice จะคล้ายกับ Array แต่เราจะ <strong>ไม่ระบุขนาด</strong> ในวงเล็บ []</p><pre>package main<br><br>import &quot;fmt&quot;<br><br>func main() {<br>    // ประกาศ Slice ของ string (ค่าเริ่มต้นคือ nil หรือว่างเปล่า)<br>    var fruits []string<br>    fmt.Println(&quot;Fruits ตอนแรก:&quot;, fruits)<br><br>    // การเพิ่มข้อมูลใน Slice ทำได้ด้วยฟังก์ชัน append()<br>    // *** สำคัญมาก: append จะคืนค่าเป็น Slice ใหม่ เราต้องรับค่ากลับมาเสมอ ***<br>    fruits = append(fruits, &quot;Apple&quot;)<br>    fruits = append(fruits, &quot;Banana&quot;)<br>    fruits = append(fruits, &quot;Mango&quot;)<br><br>    fmt.Println(&quot;Fruits ล่าสุด:&quot;, fruits)<br>    fmt.Println(&quot;ตอนนี้มีผลไม้:&quot;, len(fruits), &quot;ชนิด&quot;) // ผลลัพธ์: 3<br><br>    // การประกาศพร้อมกำหนดค่าทันที (วิธีที่นิยม)<br>    vegetables := []string{&quot;Carrot&quot;, &quot;Cabbage&quot;, &quot;Broccoli&quot;}<br>    fmt.Println(&quot;ผักที่มี:&quot;, vegetables)<br>}</pre><p>ความลับที่ทำให้ Slice ต่างจาก Array อยู่ตรงที่ ข้างใน Slice เองประกอบไปด้วย Array 1 ตัว และ มีสิ่งที่เรียกว่า <strong>Length</strong> และ <strong>Capacity </strong>คอยกำกับเอาไว้ ว่า Slice ของเราตอนนี้มีสมาชิกกี่ตัว และสามารถเก็บสมาชิกทั้งหมดได้กี่ตัว ซึ่งเราสามารถดูค่าได้ด้วยฟังก์ชัน len() และ cap()</p><p>มาทำความเข้าใจต่อว่า Length และ Capacity คืออะไร</p><p><strong>Length (เรียกสั้นๆว่า </strong><strong>len หรือ ความยาว)</strong></p><p>len คือ <strong>จำนวนสมาชิกที่มีอยู่จริง</strong> ใน Slice ณ ปัจจุบัน <strong>ลองนึกภาพตาม</strong> ถ้าเรามีตะกร้าผลไม้ และตอนนี้เราใส่แอปเปิ้ลลงไป 3 ลูก len ของตะกร้าคือ 3</p><p><strong>Capacity — </strong><strong>cap ความจุ</strong></p><p>cap คือ <strong>ขนาดของหน่วยความจำที่ Slice ได้จองไว้</strong> ใน Array ที่ซ่อนอยู่เบื้องหลัง หรือพูดง่ายๆ คือ <strong>จำนวนสมาชิกสูงสุดที่ Slice สามารถมีได้ <em>ก่อนที่</em> จะต้องไปหาหน่วยความจำใหม่ที่ใหญ่กว่าเดิม ลองนึกภาพตาม:</strong> ตะกร้าผลไม้ของเรา (Slice) อาจจะใส่ของได้สูงสุด 10 ลูก (นี่คือ cap) แต่ตอนนี้เราเพิ่งใส่ไปแค่ 3 ลูก (นี่คือ len) หมายความว่าเรายังสามารถใส่ผลไม้เพิ่มได้อีก 7 ลูก โดยไม่ต้องไปเปลี่ยนตะกร้าใบใหม่</p><p><strong><em>คำแนะนำเพิ่มเติม :</em></strong><em> </em><em>cap เกี่ยวข้องโดยตรงกับ </em><strong><em>ประสิทธิภาพ (Performance)</em></strong><em> ของโปรแกรม ถ้าหากว่าเรารู้อยู่แล้วว่า Slice ของเราจะมีสมาชิกประมาณ 1,000 ตัว การสร้าง Slice ด้วย </em><em>make([]int, 0, 1000) จะเร็วกว่าการสร้าง Slice ว่างๆ แล้วปล่อยให้มันขยายขนาดเองหลายๆ ครั้งนั่นเองครับ</em></p><p><strong>มาดูตัวอย่างการใช้งานดีกว่าครับ</strong></p><pre>package main<br><br>import &quot;fmt&quot;<br><br>func main() {<br>    // สร้าง Slice ด้วย make เพื่อกำหนด len และ cap เริ่มต้น<br>    // make([]string, 3, 5) หมายถึง:<br>    // - สร้าง Slice ของ string<br>    // - ให้มี length เริ่มต้น = 3<br>    // - ให้มี capacity เริ่มต้น = 5<br>    numbers := make([]int, 3, 5)<br><br>    fmt.Printf(&quot;เริ่มต้น -&gt; len: %d, cap: %d, slice: %v\n&quot;, len(numbers), cap(numbers), numbers)<br>    fmt.Println(&quot;----------------------------------&quot;)<br><br>    // --- ลองเพิ่มข้อมูลเข้าไป ---<br>    // ตอนนี้ len = 3, cap = 5 ยังมีที่ว่างใน capacity<br>    fmt.Println(&quot;Append 1 ตัว...&quot;)<br>    numbers = append(numbers, 40)<br>    fmt.Printf(&quot;ผลลัพธ์ -&gt; len: %d, cap: %d, slice: %v\n&quot;, len(numbers), cap(numbers), numbers)<br>    fmt.Println(&quot;สังเกต: len เพิ่ม แต่ cap เท่าเดิม เพราะยังอยู่ในความจุที่จองไว้&quot;)<br>    fmt.Println(&quot;----------------------------------&quot;)<br><br>    // --- เพิ่มอีก 1 ตัวจนเต็ม capacity ---<br>    fmt.Println(&quot;Append อีก 1 ตัว (จนเต็ม cap)...&quot;)<br>    numbers = append(numbers, 50)<br>    fmt.Printf(&quot;ผลลัพธ์ -&gt; len: %d, cap: %d, slice: %v\n&quot;, len(numbers), cap(numbers), numbers)<br>    fmt.Println(&quot;สังเกต: ตอนนี้ len เท่ากับ cap แล้ว (5/5)&quot;)<br>    fmt.Println(&quot;----------------------------------&quot;)<br><br>    // --- จุดสำคัญ! เพิ่มข้อมูลอีก 1 ตัว เกิน capacity เดิม ---<br>    fmt.Println(&quot;Append ตัวที่ทำให้เกิน cap เดิม...&quot;)<br>    numbers = append(numbers, 60)<br>    fmt.Printf(&quot;ผลลัพธ์ -&gt; len: %d, cap: %d, slice: %v\n&quot;, len(numbers), cap(numbers), numbers)<br>    fmt.Println(&quot;!!! สังเกต: Go ได้จองหน่วยความจำชุดใหม่ที่ใหญ่กว่าเดิมให้เราอัตโนมัติ !!!&quot;)<br>    fmt.Println(&quot;โดยทั่วไป cap ใหม่จะเพิ่มเป็นสองเท่าของ cap เดิม (5 -&gt; 10)&quot;)<br>}</pre><p><strong>ผลลัพธ์</strong></p><pre>เริ่มต้น -&gt; len: 3, cap: 5, slice: [0 0 0]<br>----------------------------------<br>Append 1 ตัว...<br>ผลลัพธ์ -&gt; len: 4, cap: 5, slice: [0 0 0 40]<br>สังเกต: len เพิ่ม แต่ cap เท่าเดิม เพราะยังอยู่ในความจุที่จองไว้<br>----------------------------------<br>Append อีก 1 ตัว (จนเต็ม cap)...<br>ผลลัพธ์ -&gt; len: 5, cap: 5, slice: [0 0 0 40 50]<br>สังเกต: ตอนนี้ len เท่ากับ cap แล้ว (5/5)<br>----------------------------------<br>Append ตัวที่ทำให้เกิน cap เดิม...<br>ผลลัพธ์ -&gt; len: 6, cap: 10, slice: [0 0 0 40 50 60]<br>!!! สังเกต: Go ได้จองหน่วยความจำชุดใหม่ที่ใหญ่กว่าเดิมให้เราอัตโนมัติ !!!<br>โดยทั่วไป cap ใหม่จะเพิ่มเป็นสองเท่าของ cap เดิม (5 -&gt; 10)</pre><h4>3. การ “ตัด” แบ่ง Slice (Slicing)</h4><p>นี่คือความสามารถที่เป็นที่มาของชื่อ “Slice” เราสามารถ “ตัด” บางส่วนของ Slice (หรือ Array) เพื่อสร้าง Slice ใหม่ที่มองไปยังข้อมูลชุดเดิมได้</p><p><strong>รูปแบบ:</strong> slice[low:high] (หมายถึง เอาตั้งแต่ index low ไปจนถึง <strong>ก่อน</strong> high)</p><pre>package main<br><br>import &quot;fmt&quot;<br><br>func main() {<br>    numbers := []int{10, 20, 30, 40, 50}<br>    // Index:        0,  1,  2,  3,  4<br><br>    // เอาตั้งแต่ index 1 ถึงก่อน 4 (คือ index 1, 2, 3)<br>    middle := numbers[1:4]<br>    fmt.Println(&quot;Middle:&quot;, middle) // ผลลัพธ์: [20 30 40]<br><br>    // ละ low หมายถึง เริ่มจาก 0<br>    // เอาตั้งแต่เริ่มต้น ถึงก่อน index 2 (คือ index 0, 1)<br>    firstTwo := numbers[:2]<br>    fmt.Println(&quot;First two:&quot;, firstTwo) // ผลลัพธ์: [10 20]<br><br>    // ละ high หมายถึง ไปจนสุด<br>    // เอาตั้งแต่ index 3 ไปจนสุด<br>    lastTwo := numbers[3:]<br>    fmt.Println(&quot;Last two:&quot;, lastTwo) // ผลลัพธ์: [40 50]<br>}</pre><h4>4. Array vs. Slice: สรุปความแตกต่าง</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*QjASlbzROEzgPEOLNCuWYQ.png" /></figure><p><strong>กฎง่ายๆ สำหรับมือใหม่:</strong> เมื่อไม่แน่ใจว่าจะใช้อะไร ให้เลือกใช้ <strong>Slice </strong>เนื่องจากมีความยืดหยุ่นในการใช้งานสูงกกว่า Array นั่นเองครับ</p><p>ในตอนต่อไป เราจะมาทำความรู้จักกับ <strong>Structs</strong> และ <strong>Maps</strong> เพื่อจัดการกับข้อมูลที่มีโครงสร้างซับซ้อนกันครับ</p><p>สำหรับใครที่ติดปัญหา หรือมีข้อสงสัยเกี่ยวกับการเขียน <strong>Go</strong> ก็สามารถทักไปหาผมได้ที่ <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a><strong> </strong>ได้นะครับ</p><p>สุดท้ายนี้ถ้าเห็นว่าบทความนี้น่าสนใจก็ฝากเพื่อนๆ พี่ๆ น้องๆ ช่วยแชร์ บทความนี้ไปให้เพื่อนๆ หรือคนรู้จักด้วยนะครับ แล้วก็อย่าลืม กดไลค์ กดติดตาม <a href="http://facebook.com/mosprogrammer"><strong>Fanpage : Mos Programmer</strong></a> จะได้ไม่พลาดเนื้อหาดีๆ กันนะครับ</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=030426ae9ce3" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>