# Goish: พอร์ตรันไทม์ของ Go ทั้งตัวลงใน no_std Rust

> Source: <https://dev.to/gophernment/goish-phrtranaithmkhng-go-thangtawlngain-nostd-rust-4g0n>
> Published: 2026-08-15 02:40:33+00:00

📅 เขียนเมื่อ: สิงหาคม 2026 | Goish (goish.cogentica.ai)

⚠️ โปรเจกต์เพิ่งเปิดตัว — รายละเอียด/เวอร์ชันอาจเปลี่ยนแปลง ตรวจสอบจาก GitHub ก่อนใช้งาน

ถ้าคุณเขียน Go มาสักพัก คุณน่าจะเคยอยากได้สองอย่างพร้อมกัน — **concurrency model ของ Go** (goroutine, channel, `select`

) กับ **ความปลอดภัยด้าน memory ของ Rust** (ownership, ไม่มี GC) ปกติแล้วสองอย่างนี้อยู่คนละโลก: Go ให้ runtime มาให้แต่มี garbage collector, Rust ให้ ownership มาแต่ concurrency ต้องประกอบเองจาก async/futures

มีคนพยายามเชื่อมสองโลกนี้เข้าด้วยกันแล้ว — ชื่อโปรเจกต์ว่า **Goish** ผลงานของ **Chanwit Kaewkasi** (@chanwit) วิศวกรชาวไทยจากโคราช ภายใต้บริษัท **Cogentica AI**

นิยามสั้น ๆ ที่เจ้าตัวเขียนไว้ในหน้าแรก: *"A Rust runtime for Go people"* — รันไทม์ของ Go สำหรับคนที่เขียน Go

ถ้าขยายให้ละเอียด: Goish คือการ**พอร์ต standard library และ runtime ของ Go 1.25 ลงไปใน Rust แบบ no_std** — ไม่พึ่ง glibc, ไม่พึ่ง std ของ Rust, ไม่พึ่ง Tokio, ไม่มี garbage collector มัน ship ทุกอย่างมาเองตั้งแต่

`_start`

, page allocator, size-class heap, M:N scheduler, channel, `select!`

, sync primitives, ไปจนถึง `net/http`

และ `crypto/tls`

ผลลัพธ์คือ **binary ไฟล์เดียวแบบ static** เหมือน Go — `ldd`

รันแล้วบอกว่า *"not a dynamic executable"*

แต่สิ่งที่ทำให้ Goish ต่างจากโปรเจกต์ "เขียน Go ให้เป็น Rust" ทั่วไป คือ**วิธีที่มันให้เครดิตกับต้นทาง** — เรื่องนี้แหละคือหัวใจของที่มาที่ไป

แรงจูงใจหลักไม่ใช่ "อยากให้ Rust เขียนง่ายเหมือน Go" ธรรมดา ๆ แต่เป็นเรื่องของ **compliance และ provenance**

ลองนึกภาพ: ทีมคุณเขียน Go อยู่ แล้วต้องย้ายไป Rust (ด้วยเหตุผลเรื่อง memory safety หรือนโยบายบริษัท) ระหว่างทางคุณต้อง "พอร์ต" โค้ด — เอาโค้ดจาก Go มาเขียนใหม่เป็น Rust แล้วคำถามสำคัญก็ผุดขึ้น:

AES-GCM ใน binary ตัวนี้ เป็น implementation ที่ Go review แล้ว หรือเป็นของที่เราเขียนประมาณเอา?

เครื่องมือ supply-chain ยุคปัจจุบันอย่าง **SLSA provenance** หรือ **SBOM** ตอบคำถามนี้ไม่ได้ — มันอธิบายแค่ว่า binary ถูก build มาจากไหน (builder ไหน, commit อะไร, digest อะไร) แต่**อธิบายไม่ได้ว่าโค้ดข้างในถูก port มาอย่างซื่อสัตย์แค่ไหน** SBOM จะบันทึกว่า "goish 0.1.0" แล้วจบ — มันแยกไม่ออกว่า crypto ในนั้นคือของจริงหรือของก๊อป

Goish แก้ด้วยการ**บันทึกที่มาเป็นฟังก์ชันต่อฟังก์ชัน**:

```
// go: sdk 1.25.5 crypto/internal/fips140/aes/gcm/gcm.go:31-46 newGCM
```

บรรทัดนี้เขียนไว้เหนือ port แต่ละตัว — บอกว่าโค้ดตรงนี้ port มาจากไฟล์ไหน บรรทัดไหน ใน Go 1.25.5 และมี CI ที่**เปิด Go tree ขึ้นมาเช็คทุก commit** ว่าตำแหน่งที่อ้างยังถูกต้องอยู่

ทำไมเรื่องนี้ถึงสำคัญ**ตอนนี้**? เพราะเส้นตายทางกฎหมายกำลังมา:

| วันที่ | เกิดอะไรขึ้น |
|---|---|
11 ก.ย. 2026 |
EU CRA (Cyber Resilience Act) บังคับใช้ภาระการรายงาน — แจ้งเตือน 24 ชม. / แจ้งเต็ม 72 ชม. เมื่อเจอช่องโหว่ที่ถูกโจมตีจริง |
21 ก.ย. 2026 |
ใบรับรอง FIPS 140-2 ย้ายเข้า "Historical List" — ใช้ต่อได้แต่ justify การจัดซื้อภาครัฐใหม่ไม่ได้ |
1 ม.ค. 2027 |
CNSA 2.0 กลายเป็นค่าเริ่มต้นสำหรับงาน NSS ของสหรัฐฯ |
11 ธ.ค. 2027 |
ข้อกำหนดสำคัญของ CRA รวมถึง mandate เรื่อง machine-readable SBOM |

พูดง่าย ๆ: **ถ้าสินค้าคุณต้องผ่าน compliance พวกนี้ คุณต้องพิสูจน์ได้ว่าโค้ดทุกบรรทัดมาจากไหน** — และสำหรับโค้ดที่ "แปล" มาจากที่อื่น การพิสูจน์นั้นต้องลงถึงระดับฟังก์ชัน ไม่ใช่ระดับ build

นี่คือเหตุผลที่ Goish เกิด

ส่วนนี้คือความเจ๋งทางวิศวกรรม — ถ้าไม่อยากอ่านเชิงลึก ข้ามไปหัวข้อถัดไปได้เลย

`runtime/proc.go`

Goish ไม่ได้ "เขียน scheduler ใหม่ให้คล้าย Go" — มัน**แปล runtime/proc.go ของ Go 1.25 มาทีละบรรทัด**:

`runqgrab`

/ `runqsteal`

/ `stealOrder`

)`sysmon`

ตัวจัดการ timer heap + force-preemptGoish เอา**โครงสร้าง allocator ของ Go** (mheap → mcentral → per-P mcache, 67 size classes) มาใช้ แต่**ตัด garbage collector ออก** — ให้ Rust ownership เป็นคน reclaim แทน

สำหรับ stack ของ goroutine มันใช้วิธีฉลาด: goroutine หนึ่งตัวได้ virtual reservation **1 MiB** แบบ lazy-commit (kernel ค่อย commit หน้า 4 KiB เมื่อถูกแตะจริง) — แปลว่า goroutine ที่ทำงานตื้น ๆ เสีย memory จริงแค่ประมาณหนึ่ง page และถ้าอยากได้ความหนาแน่นสุดขีด ก็ใช้ `go!(stack(2*KB), …)`

เพื่อขอ stack ขนาด 2 KiB จาก stack pool

ผลลัพธ์ตาม demo:

```
ts  vmsize_kb  vmrss_kb  vmpeak_kb  vmhwm_kb  threads
 0s    1105148      44800    1108444      49024   13   ← baseline
 2s    3069660    2406528    3069660    2406528   13   ← 1M parked
30s    3069660    2406528    3069660    2406528   13   ← steady-state
```

**goroutine หนึ่งล้านตัว บน OS thread แค่ 13 เธรด** — ~2.4 KiB RSS ต่อ goroutine

จุดเด่นที่สุดสำหรับคนเขียน Go — public API ใช้ **type ตัวพิมพ์เล็กแบบ Go** แทน type ของ Rust:

``` php
fn get(url: string) -> (int, string, string) {
    let (mut resp, err) = http::Get(url.clone());
    if err != nil {
        return (-1, fmt::Sprintf!("get %s: %v", url, err), string(""));
    }
    let (body, _) = io::ReadAll(&mut resp.Body);
    let _ = io::Closer::Close(&mut resp.Body);
    return (resp.StatusCode, string(body), resp.Header.Get("Content-Type"));
}
```

`string`

, `int`

, multi-return, `if err != nil`

— ทั้งหมดคือ Rust จริง ๆ ที่ `rustc`

compile ได้ แต่**อ่านแล้วแทบไม่ต่างจาก Go** และ `Vec<u8>`

กับ `&str`

ไม่โผล่ใน signature สาธารณะเลย

นี่คือ philosophy หลัก: **"Port first, get idiomatic later"** — พอร์ตโค้ด Go มาแบบเกือบ line-by-line ก่อน แล้วค่อย ๆ ปรับเป็น Rust idiom ทีละ module เมื่อทีมพร้อม

ส่วนที่ภาคภูมิใจที่สุดคือ `crypto/`

— **ครบ 1722/1722 declarations (100%) ทั้ง 66 packages** รวมถึง `crypto/internal/fips140*`

ทั้ง 35 packages ที่เป็น code path ของ FIPS validation และ `net/http`

ครบ **639/639 functions (100%)**

TLS 1.3 ที่รันจริงคือ `crypto/tls`

ที่ port มา verbatim — ไม่ใช่ implementation ใหม่ที่เขียนเลียนแบบ

`scratch`

/distroless container, confidential VM, appliance imageต้องการแค่ **Rust 1.79+** และ **Linux x86_64** (single-target ณ ตอนนี้)

```
git clone https://github.com/cogentica-ai/goish
cd goish

# build library
cargo build --target x86_64-unknown-linux-gnu --release

# demo: หนึ่งล้าน goroutine
cargo build --target x86_64-unknown-linux-gnu --release --example spawn_million
./examples/spawn_million.sh

# goginx: nginx clone ที่เขียนด้วย goish
cargo build --target x86_64-unknown-linux-gnu --release --example goginx
```

โค้ด "Hello" แบบ Goish หน้าตาประมาณนี้:

```
use goish::{fmt, go};

#[goish::main]
fn main() {
    go!(move || {
        fmt::Println!("hello from a goroutine");
    });
}
```

`.go`

`crypto/`

กับ `net/http`

เสร็จแล้ว แต่ `net`

, `encoding`

, `os`

ยังบางส่วนGoish ไม่ได้เป็นแค่ "Go runtime ใน Rust" — มันเป็นความพยายามตอบคำถามที่ใหญ่กว่านั้น: **เมื่อเราต้องย้ายภาษาในโลกที่มีกฎหมายบังคับเรื่องที่มาของโค้ด เราจะพิสูจน์ได้ยังไงว่าโค้ดทุกบรรทัดไว้ใจได้**

คำตอบของ Chanwit คือการพอร์ต Go แบบมี "ใบเสร็จ" ทุกบรรทัด แล้วเอา ownership ของ Rust มาแทน GC — ได้ทั้งความคุ้นเคยของ Go, ความปลอดภัยของ Rust, และหลักฐาน compliance ที่ตรวจซ้ำได้

โปรเจกต์นี้เพิ่งเปิด (สิงหาคม 2026) และยังพัฒนาอย่างต่อเนื่อง ถ้าสนใจเข้าไปดูได้ที่:

**เครดิต:** บทความนี้อ้างอิงข้อมูลจากเว็บไซต์ goish.cogentica.ai และ README ของ github.com/cogentica-ai/goish — โปรเจกต์โดย **Chanwit Kaewkasi** (@chanwit) ภายใต้ **Cogentica AI** (ประเทศไทย)

⚠️ Goish ไม่เกี่ยวข้องกับ Google หรือ Go project — "Go" เป็นเครื่องหมายการค้าของ Google LLC
