1. Giriş
Expr, Go diline özgü basit sözdizimi ve güçlü performans özellikleri ile bilinen bir dinamik yapılandırma çözümüdür. Expr ifade motorunun çekirdeği, güvenlik, hız ve sezgisellik üzerine odaklanmış olup, erişim kontrolü, veri filtreleme ve kaynak yönetimi gibi senaryolar için uygun hale getirilmiştir. Go'ya uygulandığında, Expr uygulamaların dinamik kuralları işleme yeteneğini büyük ölçüde artırır. Diğer dillerdeki yorumlayıcılar veya komut dosyası motorlarının aksine, Expr statik tür denetimi benimser ve yürütme için bayt kodu üretir, böylelikle performansı ve güvenliği sağlar.
2. Expr'in Yüklenmesi
Expr ifade motorunu Go dilinin paket yönetim aracı go get
kullanılarak yükleyebilirsiniz:
go get github.com/expr-lang/expr
Bu komut, Expr kütüphane dosyalarını indirir ve bunları Go projenize yükleyerek, Go kodunuzda Expr'i içe aktarmanıza ve kullanmanıza olanak tanır.
3. Hızlı Başlangıç
3.1 Temel İfadelerin Derlenmesi ve Çalıştırılması
Basit bir örnek ile başlayalım: Basit bir ifade yazma, derleme ve ardından sonucu elde etmek için çalıştırma.
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
// Temel bir toplama ifadesini derleme
program, err := expr.Compile(`2 + 2`)
if err != nil {
panic(err)
}
// Ortam iletişimini geçmeden derlenmiş ifadeyi çalıştırma, çünkü burada değişkenlere ihtiyaç yok
output, err := expr.Run(program, nil)
if err != nil {
panic(err)
}
// Sonucu yazdırma
fmt.Println(output) // 4 çıktısını verir
}
Bu örnekte, 2 + 2
ifadesi yürütülebilir bayt koda derlenir, ardından çıktı üretmek için yürütülür.
3.2 Değişken İfadelerin Kullanımı
Daha sonra, değişken içeren bir ortam oluşturacağız, bu değişkenleri kullanan bir ifade yazacağız, bu ifadeyi derleyip çalıştıracağız.
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
// Değişkenler içeren bir ortam oluşturma
env := map[string]interface{}{
"foo": 100,
"bar": 200,
}
// Ortamı kullanan değişken içeren bir ifadeyi derleme
program, err := expr.Compile(`foo + bar`, expr.Env(env))
if err != nil {
panic(err)
}
// İfadeyi çalıştırma
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
// Sonucu yazdırma
fmt.Println(output) // 300 çıktısını verir
}
Bu örnekte, env
ortamı foo
ve bar
değişkenlerini içerir. foo + bar
ifadesi derleme sırasında değişkenlerin tiplerini çevrimdışı olarak alır ve çalışma zamanında bu değişkenlerin değerlerini kullanarak ifadenin sonucunu değerlendirir.
4. Detaylı Olarak Expr Sözdizimi
4.1 Değişkenler ve Söz Dizimi
Expr ifade motoru, sayılar, dizeler ve boolean değerler gibi yaygın veri türü literallerini işleyebilir. Literaller, kod içinde doğrudan yazılan veri değerlerini ifade eder, örneğin 42
, "hello"
ve true
.
Sayılar
Expr'de tamsayıları ve ondalık sayıları doğrudan yazabilirsiniz:
42 // Tamsayı 42'yi temsil eder
3.14 // Ondalık sayı 3.14'ü temsil eder
Dizeler
Dize literalleri çift tırnak "
veya ters tırnak `` ile çevrilidir. Örneğin:
"hello, world" // Çift tırnak içinde çevrili dize, kaçış karakterlerini destekler
`hello, world` // Ters tırnak içinde çevrili dize, kaçış karakterlerini desteklemeden dize biçimini korur
Boolean Değerler
Yalnızca iki boolean değer vardır, true
ve false
, mantıksal doğru ve yanlışı temsil eder:
true // Boolean doğru değeri
false // Boolean yanlış değeri
Değişkenler
Expr ayrıca ortamdaki değişkenlerin tanımlanmasına izin verir ve daha sonra ifadede bu değişkenlere başvurabilirsiniz. Örneğin:
env := map[string]interface{}{
"age": 25,
"name": "Alice",
}
Ardından ifadede age
ve name
e başvurabilirsiniz:
age > 18 // Yaş 18'den büyük mü diye kontrol etme
name == "Alice" // İsim "Alice"e eşit mi diye belirleme
4.2 Operatörler
Expr ifade motoru, aritmetik operatörler, mantıksal operatörler, karşılaştırma operatörleri, ve küme operatörleri gibi çeşitli operatörleri destekler.
Aritmetik ve Mantıksal Operatörler
Aritmetik operatörler toplama (+
), çıkarma (-
), çarpma (*
), bölme (/
) ve mod (%
) içerir. Mantıksal operatörler ise mantıksal VE (&&
), mantıksal VEYA (||
) ve mantıksal DEĞİL (!
) gibi operatörleri içerir, örneğin:
2 + 2 // Sonuç 4'tür
7 % 3 // Sonuç 1'dir
!true // Sonuç false'tır
age >= 18 && name == "Alice" // Yaş 18'den küçük değilse ve isim "Alice" ise kontrol edin
Karşılaştırma Operatörleri
Karşılaştırma operatörleri eşit (==
), eşit değil (!=
), küçük (<
), küçük eşit (<=
), büyük (>
), ve büyük eşit (>=
) gibi iki değeri karşılaştırmak için kullanılır:
age == 25 // Yaş 25'e eşit mi diye kontrol edin
age != 18 // Yaş 18'e eşit değil mi diye kontrol edin
age > 20 // Yaş 20'den büyük mü diye kontrol edin
Set Operatörleri
Expr ayrıca setlerle çalışmak için bazı operatörler sağlar, örneğin bir elemanın set içinde olup olmadığını kontrol etmek için in
kullanılır. Setler array'ler, slice'lar ya da map'ler olabilir:
"user" in ["user", "admin"] // "user" array içinde olduğu için true,
3 in {1: true, 2: false} // 3 map içinde bir key değil, bu yüzden false
Ayrıca all
, any
, one
ve none
gibi bazı gelişmiş set işlem fonksiyonları bulunmaktadır, bu fonksiyonlar anonim fonksiyonları (lambda) kullanmayı gerektirir:
all(tweets, {.Len <= 240}) // Tüm tweet'lerin Len alanı 240 karakteri geçmiyor mu diye kontrol edin
any(tweets, {.Len > 200}) // Tweet'ler arasında Len alanı 200 karakteri geçen var mı diye kontrol edin
Üye Operatörü
Expr ifade dilinde üye operatörü, Go dilindeki struct
'ın özelliklerine erişmemize olanak tanır. Bu özellik, Expr'in doğrudan karmaşık veri yapılarını manipüle etmesine olanak tanır ve çok esnek ve pratik hale getirir.
Üye operatörünü kullanmak çok basittir, sadece .
operatörünü kullanın ve ardından özellik ismini yazın. Örneğin, eğer aşağıdaki struct
'e sahipsek:
type User struct {
Name string
Age int
}
User
yapısının Name
özelliğine erişmek için şöyle bir ifade yazabilirsiniz:
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) // Çıktı: Alice
nil Değerlerinin İşlenmesi
Özelliklere erişirken nesnenin nil
olabileceği durumlarla karşılaşabilirsiniz. Expr, güvenli bir özellik erişimi sağlar, böylece struct veya iç içe özellik nil
olsa bile çalışma zamanı hata atfetmez.
Özelliklere başvurmak için ?.
operatörünü kullanın. Nesne nil
ise hata fırlatmak yerine nil döndürecektir.
author.User?.Name
Eşdeğer ifade
author.User != nil ? author.User.Name : nil
??
operatörü genellikle varsayılan değerleri döndürmek içindir:
author.User?.Name ?? "Anonymous"
Eşdeğer ifade
author.User != nil ? author.User.Name : "Anonymous"
Pipe Operator
Expr'deki pipe operatörü (|
), bir ifadenin sonucunu başka bir ifadenin parametresi olarak iletmek için kullanılır. Bu, Unix kabuğundaki pipe işlemine benzer ve birden çok işlevsel modülün bir işleme hattı oluşturmak üzere birbirine bağlanmasına olanak tanır. Expr'de kullanarak daha net ve özlü ifadeler oluşturmak mümkündür.
Örneğin, bir kullanıcının adını almak için bir işlev ve bir karşılama mesajı için bir şablonumuz olsun:
env := map[string]interface{}{
"user": User{Name: "Bob", Age: 30},
"get_name": func(u User) string { return u.Name },
"greet_msg": "Merhaba, %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) // Çıktı: Merhaba, Bob!
Bu örnekte, önce get_name(user)
ile kullanıcının adını alıyoruz, ardından ismi sprintf
işlevine |
pipe operatörü kullanarak ileterek son karşılama mesajını oluşturuyoruz.
Pipe operatörü kullanarak kodumuzu modüler hale getirebilir, kod yeniden kullanılabilirliğini artırabilir ve ifadeleri daha okunabilir hale getirebiliriz.
4.3 İşlevler
Expr, yerleşik işlevleri ve özel işlevleri destekleyerek ifadeleri daha güçlü ve esnek hale getirir.
Yerleşik İşlevlerin Kullanımı
len
, all
, none
, any
gibi yerleşik işlevler doğrudan ifade içinde kullanılabilir.
// Yerleşik bir işlevin kullanım örneği
program, err := expr.Compile(`all(users, {.Age >= 18})`, expr.Env(env))
if err != nil {
panic(err)
}
// Not: burada env değişkeninin users'ı içermesi gerekir ve her kullanıcının Age özelliğine sahip olması gerekir
output, err := expr.Run(program, env)
fmt.Print(output) // Eğer env içindeki tüm kullanıcıların yaşı 18 veya üzeriyse, true dönecektir
Özel İşlevlerin Tanımlanması ve Kullanılması
Expr'de, çevre eşlemesine işlev tanımlamalarını aktararak özel işlevler oluşturabilirsiniz.
// Özel işlev örneği
env := map[string]interface{}{
"greet": func(name string) string {
return fmt.Sprintf("Merhaba, %s!", name)
},
}
program, err := expr.Compile(`greet("Dünya")`, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
fmt.Print(output) // Çıktı: Merhaba, Dünya!
Expr'deki işlevleri kullanırken, kodunuzu modüler hale getirebilir ve karmaşık mantığı ifadelere entegre edebilirsiniz. Değişkenler, operatörler ve işlevlerin birleştirilmesiyle, Expr güçlü ve kullanımı kolay bir araç haline gelir. Expr çevresini oluştururken ve ifadeleri çalıştırırken her zaman veri türü güvenliğini sağlamayı unutmayın.
5. Yerleşik İşlev Belgelendirmesi
Expr ifade motoru, geliştiricilere çeşitli karmaşık senaryolarla başa çıkmak için zengin bir yerleşik işlev kümesi sunar. Aşağıda, bu yerleşik işlevleri ve kullanımlarını detaylandıracağız.
all
all
işlevi, bir koleksiyondaki tüm öğelerin belirli bir koşulu karşılayıp karşılamadığını kontrol etmek için kullanılır. İki parametre alır: koleksiyon ve koşul ifadesi.
// Tüm tweetlerin içeriğinin 240 karakterden az olduğunu kontrol etme
code := `all(tweets, len(.Content) < 240)`
any
all
ile benzer şekilde, any
işlevi bir koleksiyondaki herhangi bir öğenin bir koşulu karşılayıp karşılamadığını kontrol etmek için kullanılır.
// Herhangi bir tweetin içeriğinin 240 karakterden fazla olduğunu kontrol etme
code := `any(tweets, len(.Content) > 240)`
none
none
işlevi, bir koleksiyondaki hiçbir öğenin belirli bir koşulu karşılamadığını kontrol etmek için kullanılır.
// Tekrarlanan hiçbir tweetin olmadığını kontrol etme
code := `none(tweets, .IsRepeated)`
one
one
işlevi, bir koleksiyondaki yalnızca bir öğenin belirli bir koşulu karşıladığını doğrulamak için kullanılır.
// Yalnızca bir tweetin belirli bir anahtar kelimeyi içerdiğini kontrol etme
code := `one(tweets, contains(.Content, "anahtar kelime"))`
filter
filter
işlevi, belirli bir koşulu karşılayan koleksiyon öğelerini filtrelemek için kullanılır.
// Öncelikli olarak işaretlenmiş tüm tweetleri filtreleme
code := `filter(tweets, .IsPriority)`
map
map
işlevi, bir koleksiyondaki öğeleri belirtilen bir yönteme göre dönüştürmek için kullanılır.
// Tüm tweetlerin yayın zamanını biçimlendirme
code := `map(tweets, {.PublishTime: Format(.Date)})`
len
len
fonksiyonu, bir koleksiyonun veya dizenin uzunluğunu döndürmek için kullanılır.
// Kullanıcı adının uzunluğunu alma
code := `len(username)`
contains
contains
fonksiyonu, bir dizenin belirli bir alt dizeyi içerip içermediğini veya bir koleksiyonun belirli bir öğeyi içerip içermediğini kontrol etmek için kullanılır.
// Kullanıcı adının yasaklı karakterleri içerip içermediğini kontrol etme
code := `contains(username, "yasaklı karakterler")`
Yukarıda bahsedilenler, Expr ifade motoru tarafından sağlanan yerleşik fonksiyonların sadece bir parçasıdır. Bu güçlü fonksiyonlarla, verileri ve mantığı daha esnek ve verimli bir şekilde işleyebilirsiniz. Daha detaylı fonksiyon listesi ve kullanım talimatları için lütfen resmi Expr belgelerine başvurun.