1. การแนะนำ
Expr เป็นโซลูชันการกำหนดค่าแบบไดนามิกที่ออกแบบมาสำหรับภาษา Go ซึ่งโดดเด่นด้วยไวยากรง่าย และคุณสมบัติประสิทธิภาพที่มีอยู่ ฝั่งหลักของเครื่องมือการแสดงผล Expr มุ่งไปที่ความปลอดภัย ความเร็ว และความสะดวก ซึ่งทำให้เหมาะสำหรับสถานการณ์ทั้งหมด เช่น การควบคุมการเข้าถึง การกรองข้อมูล และการจัดการทรัพยากร การนำ Expr มาใช้ใน Go จะเสริมความสามารถของแอปพลิเคชันในการจัดการกฎไดนามิกอย่างมาก ไม่เหมือนกับตัวแปลหรือเครื่องมือสคริปต์ในภาษาอื่น ที่ Expr ใช้การตรวจสอบชนิดของข้อมูลแบบสถิตและสร้างไบต์โค้ดสำหรับการประมวลผล ทำให้มั่นใจได้ทั้งการทำงานและความปลอดภัย
2. การติดตั้ง Expr
คุณสามารถติดตั้งเครื่องมือการแสดงผล Expr โดยใช้เครื่องมือการจัดการแพ็กเกจของ Go language คือ go get
:
go get github.com/expr-lang/expr
คำสั่งนี้จะดาวน์โหลดไฟล์ไลบรารี Expr และติดตั้งไฟล์เหล่านี้ลงในโปรเจค Go ของคุณ ทำให้คุณสามารถนำ Expr เข้ามาใช้ในโค้ด Go ของคุณได้
3. เริ่มต้นอย่างรวดเร็ว
3.1 คอมไพล์และรันนิ่งส่วนพื้นฐานขององค์ประกอบ
เริ่มต้นด้วยตัวอย่างพื้นฐาน: เขียนสมการง่าย คอมไพล์และรันเพื่อรับผลลัพธ์
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
// คอมไพล์สมการการบวกพื้นฐาน
โปรแกรม, ข้อผิดพลาด := expr.Compile(`2 + 2`)
if ข้อผิดพลาด != nil {
panic(ข้อผิดพลาด)
}
// รันสมการที่คอมไพล์ไว้โดยไม่ต้องส่ง environment เนื่องจากไม่จำเป็นต้องใช้ตัวแปรที่นี่
ผลลัพธ์, ข้อผิดพลาด := expr.Run(โปรแกรม, nil)
if ข้อผิดพลาด != nil {
panic(ข้อผิดพลาด)
}
// พิมพ์ผลลัพธ์
fmt.Println(ผลลัพธ์) // แสดงผลเป็น 4
}
ในตัวอย่างนี้ สมการ 2 + 2
ถูกคอมไพล์เป็นไบต์โค้ดที่สามารถรันได้เพื่อได้ผลลัพธ์
3.2 การใช้งานสมการที่มีตัวแปร
ต่อมา เราจะสร้าง environment ที่มีตัวแปร และเขียนสมการโดยใช้ตัวแปรเหล่านั้น จากนั้นคอมไพล์และรันสมการนี้
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
// สร้าง environment ที่มีตัวแปร
env := map[string]interface{}{
"foo": 100,
"bar": 200,
}
// คอมไพล์สมการที่ใช้ตัวแปรจาก environment
โปรแกรม, ข้อผิดพลาด := expr.Compile(`foo + bar`, expr.Env(env))
if ข้อผิดพลาด != nil {
panic(ข้อผิดพลาด)
}
// รันสมการ
ผลลัพธ์, ข้อผิดพลาด := expr.Run(โปรแกรม, env)
if ข้อผิดพลาด != nil {
panic(ข้อผิดพลาด)
}
// พิมพ์ผลลัพธ์
fmt.Println(ผลลัพธ์) // แสดงผลเป็น 300
}
ในตัวอย่างนี้ environment env
มีตัวแปร foo
และ bar
สมการ foo + bar
จะใช้ประเภทของ foo
และ bar
จาก environment ในขณะคอมไพล์ และใช้ค่าของตัวแปรเหล่านั้นในระหว่างการประเมินผลลัพธ์ของสมการ
4. รายละเอียด Syntax ของ Expr
4.1 ตัวแปรและลิเตอรอล
เครื่องมือการแสดงผล Expr สามารถจัดการกับลิเตอรอลของชนิดข้อมูลทั่วไป เช่น ตัวเลข สตริง และค่าบูลีน ลิเตอรอลเป็นค่าข้อมูลที่เขียนเลยไปในโค้ดโดยตรง เช่น 42
, "hello"
, และ true
ตัวเลข
ใน Expr คุณสามารถเขียนจำนวนเต็มและจำนวนทศนิยมโดยตรง:
42 // แทนค่าจำนวนเต็ม 42
3.14 // แทนค่าจำนวนทศนิยม 3.14
สตริง
ลิเตอรอลสตริงถูกล้อมรอบด้วยเครื่องหมายคำพูน "
หรือเครื่องหมาย c backticks `` ตัวอย่างเช่น:
"hello, world" // สตริงที่ล้อมรอบด้วยเครื่องหมายคำพูน รองรับการใช้ตัวอักษรพิเศษ
`hello, world` // สตริงที่ล้อมรอบด้วยเครื่องหมาย c backticks รักษารูปแบบของสตริงโดยไม่สนับสนุนตัวอักษรพิเศษ
ค่าบูลีน
มีเพียงสองค่าบูลีน คือ true
และ false
ที่แทนค่าlogic true
และ false
:
true // ค่าบูลีน true
false // ค่าบูลีน false
ตัวแปร
Expr ยังอนุญาตให้กำหนดตัวแปรใน environment และอ้างถึงตัวแปรเหล่านั้นในสมการ เช่น:
env := map[string]interface{}{
"age": 25,
"name": "Alice",
}
จากนั้นในสมการ คุณสามารถอ้างถึง age
และ name
:
age > 18 // ตรวจสอบว่าอายุมากกว่า 18 หรือไม่
name == "Alice" // กำหนดว่าชื่อเท่ากับ "Alice"
4.2 ตัวดำเนินการ
Expr เป็นเครื่องมือการแสดงผลที่รองรับตัวดำเนินการต่างๆ เช่น ตัวดำเนินการกวาดวิตร์ เชื่อมต่อดีย์ยังกวาดวิตร์ ตัวดำเนินการเปรียบเทียบ และตัวดำเนินการเซต ฯลฯ
ตัวดำเนินการทางคณิตศาสตร์และตรรกะ
ตัวดำเนินการทางคณิตศาสตร์รวมถึงการบวก (+
), การลบ (-
), การคูณ (*
), การหาร (/
), และเศษทศนิยม (%
) ตัวดำเนินการทางตรรกะรวมถึง และ (&&
), หรือ (||
), และ ไม่ (!
), ตัวอย่างเช่น:
2 + 2 // ผลลัพธ์คือ 4
7 % 3 // ผลลัพธ์คือ 1
!true // ผลลัพธ์คือ false
age >= 18 && name == "Alice" // ตรวจสอบว่าอายุไม่น้อยกว่า 18 และชื่อเป็น "Alice"
ตัวดำเนินการเปรียบเทียบ
ตัวดำเนินการเปรียบเทียบรวมถึงเท่ากับ (==
), ไม่เท่ากับ (!=
), น้อยกว่า (<
), น้อยกว่าหรือเท่ากับ (<=
), มากกว่า (>
), และ มากกว่าหรือเท่ากับ (>=
), ใช้สำหรับเปรียบเทียบค่าสองค่า:
age == 25 // ตรวจสอบว่าอายุเท่ากับ 25
age != 18 // ตรวจสอบว่าอายุไม่เท่ากับ 18
age > 20 // ตรวจสอบว่าอายุมากกว่า 20
ตัวดำเนินการเซ็ต
Expr ยังมีตัวดำเนินการบางตัวสำหรับใช้กับเซ็ต เช่น in
เพื่อตรวจสอบว่าสมาชิกหนึ่งอยู่ในเซ็ตหรือไม่ เซ็ตสามารถเป็นอาร์เรย์ (arrays), สไลซ์ (slices), หรือแม็พ (maps):
"user" in ["user", "admin"] // true, เพราะ "user" อยู่ในอาร์เรย์
3 in {1: true, 2: false} // false, เพราะ 3 ไม่ใช่คีย์ในแม็พ
ยังมีฟังก์ชันจัดการเซ็ตขั้นสูงบางตัว เช่น all
, any
, one
, และ none
, ซึ่งต้องใช้ฟังก์ชันแบบนามธรรม (lambda):
all(tweets, {.Len <= 240}) // ตรวจสอบว่าฟิลด์ Len ของทวีตทั้งหมดไม่เกิน 240
any(tweets, {.Len > 200}) // ตรวจสอบว่ามีฟิลด์ Len ในทวีตที่เกิน 200
ตัวดำเนินการสมาชิก
ในภาษาแสดงนิพจน์ Expr ตัวดำเนินการสมาชิกช่วยให้เราเข้าถึงคุณสมบัติของ struct
ใน Go language คุณสมบัตินี้ช่วยให้ Expr สามารถจัดการโครงสร้างข้อมูลที่ซับซ้อนโดยตรง ทำให้มีความยืดหยุ่นและปฏิบัติได้มาก
การใช้ตัวดำเนินการสมาชิกง่ายมาก เพียงใช้ตัวดำเนินการ .
ตามด้วยชื่อคุณสมบัติ เช่น ถ้าเรามี struct
ต่อไปนี้:
type User struct {
Name string
Age int
}
คุณสามารถเขียนนิพจน์เพื่อเข้าถึงคุณสมบัติ Name
ของโครงสร้าง User
อย่างไรก็ตาม:
env := map[string]interface{}{
"user": User{Name: "Alice", Age: 25},
}
code := `user.Name`
program, err := expr.Compile(code, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output) // ผลลัพธ์: Alice
การจัดการค่าที่เป็น nil
เมื่อเข้าถึงคุณสมบัติ คุณอาจพบสถานการณ์ที่วัตถุเป็น nil
Expr มีการเข้าถึงคุณสมบัติอย่างปลอดภัย เพื่อให้วัตถุหรือคุณสมบัติซ้อน ๆ เป็น nil
มันจะไม่สร้างข้อผิดพลาดขณะทำงาน
ใช้ตัวดำเนินการ ?.
เพื่ออ้างถึงคุณสมบัติ หากวัตถุเป็น nil มันจะส่งกลับ nil แทนที่จะสร้างข้อผิดพลาด
author.User?.Name
นิพจน์เทียบเท่า
author.User != nil ? author.User.Name : nil
การใช้ตัวดำเนินการ ??
ใช้สำหรับการส่งค่าเริ่มต้น:
author.User?.Name ?? "Anonymous"
นิพจน์เทียบเท่า
author.User != nil ? author.User.Name : "Anonymous"
ตัวดำเนินการท่อ (Pipe Operator)
ตัวดำเนินการท่อ (|
) ใน Expr ใช้ส่งผลลัพธ์ของนิพจน์หนึ่งเป็นพารามิเตอร์ให้กับนิพจน์อื่น ๆ ซึ่งคล้ายกับการดำเนินการท่อใน Unix shell ซึ่งอนุญาตให้มีโมดูลฟังก์ชันและโมดูลฟังก์ชันหลายรายการถูกเชื่อมต่อเข้าด้วยกันเพื่อสร้างท่อประมวลผล ใน Expr การใช้มันสามารถสร้างนิพจนีย์ที่ชัดเจนและกระชับมากขึ้น
ตัวอย่างเช่น หากเรามีฟังก์ชันที่ใช้ในการรับชื่อของผู้ใช้และเทมเพลตสำหรับข้อความต้อนรับ:
env := map[string]interface{}{
"user": User{Name: "Bob", Age: 30},
"get_name": func(u User) string { return u.Name },
"greet_msg": "Hello, %s!",
}
code := `get_name(user) | sprintf(greet_msg)`
program, err := expr.Compile(code, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output) // ผลลัพธ์: Hello, Bob!
ในตัวอย่างนี้ เราเริ่มต้นด้วยการรับชื่อของผู้ใช้ผ่าน get_name(user)
จากนั้นส่งชื่อไปยังฟังก์ชัน sprintf
โดยใช้ตัวดำเนินการท่อ |
เพื่อสร้างข้อความต้อนรับสุดท้าย
การใช้ตัวดำเนินการท่อสามารถทำให้รหัสของเราเป็นโมดูลได้อีกด้วย เพิ่มความสามารถในการนำรหัสขึ้นมาใช้ใหม่และทำให้นิพจนีย์เป็นที่อ่านเข้าใจมากขึ้น
4.3 ฟังก์ชัน
Expr รองรับฟังก์ชันที่ซึ่งเป็นซับเปอร์เพาเวอรีเดียวกันและฟังก์ชันที่กำหนดเอง ทำให้นิพจนีย์มีความสามารถและความยืดหยุ่นมากขึ้น
การใช้ Built-in Functions
Built-in functions เช่น len
, all
, none
, any
, เป็นต้น สามารถใช้โดยตรงในนิพจน์
// ตัวอย่างการใช้ built-in function
program, err := expr.Compile(`all(users, {.Age >= 18})`, expr.Env(env))
if err != nil {
panic(err)
}
// หมายเหตุ: ที่นี่ env ต้องมีตัวแปร users และแต่ละ user จะต้องมีคุณสมบัติ Age
output, err := expr.Run(program, env)
fmt.Print(output) // หากทุก user ใน env มีอายุ 18 ขึ้นไป มันจะส่งค่าเป็น true
วิธีการกำหนดและใช้ฟังก์ชันที่กำหนดเอง
ใน Expr คุณสามารถสร้างฟังก์ชันที่กำหนดเองได้โดยการส่งการกำหนดฟังก์ชันไปยังการจัดสรรแวดล้อม
// ตัวอย่างของการใช้ฟังก์ชันที่กำหนดเอง
env := map[string]interface{}{
"greet": func(name string) string {
return fmt.Sprintf("Hello, %s!", name)
},
}
program, err := expr.Compile(`greet("World")`, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
fmt.Print(output) // คืนค่าเป็น Hello, World!
เมื่อใช้ฟังก์ชันใน Expr คุณสามารถทำให้รหัสของคุณเป็นโมดูลและรวมตรรกะความซับซ้อนเข้าในนิพจนีย์ โดยการผสมค่าตัวแปร ตัวดำเนินการ และฟังก์ชัน Expr กลายเป็นเครื่องมือที่มีความสามารถและใช้ง่าย อย่าลืมเสมอให้มั่นใจในความปลอดภัยของชนิดเมื่อสร้างแวดล้อม Expr และในการรันนิพจน์
5. คู่มือ Built-in Function
เครื่องมือนิพจน์ Expr มีฟังก์ชันที่กำหนดเองที่มีความหลากหลาย สำหรับการจัดการสถานการณ์ที่ซับซ้อน ต่อไปเราจะรายละเอียดเกี่ยวกับฟังก์ชันที่กำหนดเองเหล่านี้และการใช้งานของมัน
all
ฟังก์ชัน all
สามารถใช้ในการตรวจสอบว่าทุกองค์ประกอบในคอลเล็กชันทำให้เงื่อนไขที่กำหนดได้ มันรับพารามิเตอร์สองตัว: คอลเล็กชันและนิพจน์เงื่อนไข
// ตรวจสอบว่าทุกทวีตมีความยาวเนื้อหาน้อยกว่า 240
code := `all(tweets, len(.Content) < 240)`
any
คล้ายกับ all
ฟังก์ชัน any
ใช้ในการตรวจสอบว่าสมาชิกใดสมาชิกหนึ่งในคอลเล็กชันทำให้เงื่อนไขที่กำหนดได้
// ตรวจสอบว่าทวีตใดทวีตหนึ่งมีความยาวเนื้อหามากกว่า 240
code := `any(tweets, len(.Content) > 240)`
none
ฟังก์ชัน none
ใช้ในการตรวจสอบว่าไม่มีสมาชิกใดสมาชิกหนึ่งในคอลเล็กชันทำให้เงื่อนไขที่กำหนดได้
// การตรวจสอบว่าไม่มีทวีตที่ซ้ำ
code := `none(tweets, .IsRepeated)`
one
ฟังก์ชัน one
ใช้ในการยืนยันว่ามีสมาชิกเพียงหนึ่งตัวในคอลเล็กชันทำให้เงื่อนไขที่กำหนดได้
// ตรวจสอบว่ามีเพียงทวีตเท่านั้นที่มีคำหลักเฉพาะ
code := `one(tweets, contains(.Content, "keyword"))`
filter
ฟังก์ชัน filter
สามารถกรององค์ประกอบในคอลเล็กชันที่ทำให้เงื่อนไขที่กำหนดได้
// การกรองทวีตทุกอันที่มีเครื่องหมายที่ระบุว่าเป็นลำดับความสำคัญออก
code := `filter(tweets, .IsPriority)`
map
ฟังก์ชัน map
ใช้ในการแปลงองค์ประกอบในคอลเล็กชันตามวิธีที่ระบุ
// การจัดรูปแบบเวลาเผยแพร่ของทวีตทุกอัน
code := `map(tweets, {.PublishTime: Format(.Date)})`
len
ฟังก์ชัน len
ใช้สำหรับคืนค่าความยาวของคอลเล็กชันหรือสตริง
// หาความยาวของชื่อผู้ใช้
code := `len(username)`
contains
ฟังก์ชัน contains
ใช้สำหรับตรวจสอบว่าสตริงบางส่วนมีอยู่ในสตริงหรือไม่ หรือว่าคอลเล็กชันมีสมาชิกบางตัวอยู่ในนั้นหรือไม่
// ตรวจสอบว่าชื่อผู้ใช้มีอักขระที่ไม่ถูกต้องหรือไม่
code := `contains(username, "illegal characters")`
สิ่งที่กล่าวมาข้างต้นนั้นเป็นเพียงส่วนหนึ่งของฟังก์ชันที่ใช้งานได้ภายในเครื่องมือ Expr ด้วยฟังก์ชันที่มีประสิทธิภาพในการจัดการข้อมูลและตรรกะได้อย่างยืดหยุ่นและมีประสิทธิภาพ สำหรับรายการของฟังก์ชันและคำแนะนำในการใช้ กรุณาอ่านเพิ่มเติมที่ เอกสารอ้างอิงทางการของ Expr