This notebook demostrates the basic usage of lgo. You can use all Go (golang) language features with lgo.
After you learn this notebook, see these notebooks to understand advanced topics.
Displays the environment where this notebook is executed.
import (
"fmt"
"os"
"os/user"
"runtime"
)
{
user, _ := user.Current()
fmt.Printf("Go: %s (%s_%s)\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
fmt.Printf("User: %s\n", user.Username)
wd, _ := os.Getwd()
fmt.Printf("Working dir: %s\n", wd)
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
}
Go: go1.9.2 (linux_amd64) User: gopher Working dir: /examples NumCPU: 2
// naiveFib calculates the n-th fibonacci number
func naiveFib(n int) int {
if n > 1 {
return naiveFib(n - 1) + naiveFib(n - 2)
}
return 1
}
naiveFib(20)
10946
import "fmt"
n := 10
if n > 0 {
fmt.Println("n is positive:", n)
} else {
fmt.Println("n is not positive:", n)
}
n is positive: 10
sum := 0
for i := 1; i <= n; i++ {
sum += i
}
sum
55
switch sum {
case 55:
fmt.Println("OK")
default:
fmt.Println("Fail")
}
OK
import (
"fmt"
"math"
)
fmt.Printf("sin(pi/3) == %f\n", math.Sin(math.Pi/3))
fmt.Printf("cos(pi/3) == %f\n", math.Cos(math.Pi/3))
fmt.Printf("sqrt(3)/2 == %f\n", math.Sqrt(3)/2)
fmt.Printf("log(e^2) == %f\n", math.Log(math.E * math.E))
sin(pi/3) == 0.866025 cos(pi/3) == 0.500000 sqrt(3)/2 == 0.866025 log(e^2) == 2.000000 21 <nil>
import (
"math/rand"
"time"
)
rand.Seed(time.Now().UnixNano())
r := rand.Int()
r
636250466556259171
r % 10000
9171
start := time.Now()
start
2017-10-16 13:17:47.637999781 +0000 UTC m=+6.138424087
end := time.Now()
end
2017-10-16 13:17:48.311503905 +0000 UTC m=+6.811928266
fmt.Printf("end - start = %v", end.Sub(start))
end - start = 673.504179ms26 <nil>
type person struct {
name string
age int
}
func (p *person) Hello() string {
return fmt.Sprintf("Hello! Name: %s, Age: %d", p.name, p.age)
}
p := person{"Alice", 12}
fmt.Printf("p.name = %q\n", p.name)
fmt.Printf("p.Hello() == %q\n", p.Hello())
p.name = "Alice" p.Hello() == "Hello! Name: Alice, Age: 12" 43 <nil>
type hello interface {
Hello() string
}
func printHello(h hello) {
if _, ok := h.(*person); ok {
fmt.Println("h is *person")
}
fmt.Printf("h.Hello() == %q\n", h.Hello())
}
p := person{"Alice", 12}
printHello(&p)
h is *person h.Hello() == "Hello! Name: Alice, Age: 12"
Of course, you can interacts with Go libraries using interfaces
// You can pass a type defined in lgo as an interface defined in Go.
import (
"bytes"
"fmt"
"io"
)
type myReader struct {
content string
idx int
}
func (r *myReader) Read(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
if r.idx >= len(r.content) {
return 0, io.EOF
}
p[0] = r.content[r.idx]
fmt.Printf("Read %q\n", r.content[r.idx])
r.idx++
return 1, nil
}
{
r := myReader{content: "Hello!"}
var buf bytes.Buffer
io.Copy(&buf, &r)
fmt.Printf("buf == %q\n", buf.String())
}
Read 'H' Read 'e' Read 'l' Read 'l' Read 'o' Read '!' buf == "Hello!"
// You can pass a struct defined in Go as an interface defined in lgo too.
import (
"bytes"
"fmt"
)
type withLen interface {
Len() int
}
func printLen(l withLen) {
fmt.Printf("Len(%v) == %d\n", l, l.Len())
}
{
var buf bytes.Buffer
buf.WriteString("01234")
printLen(&buf)
buf.WriteString("56789")
printLen(&buf)
}
Len(01234) == 5 Len(0123456789) == 10
A code block in lgo is executed code inside a function with no return value.
You can exit code by return
statement. Also, you can use defer
to execute functions after a code block.
// return
if true {
fmt.Println("return!")
return
}
fmt.Println("continue!")
return!
fmt.Println("start")
defer fmt.Println("defer (1)")
defer fmt.Println("defer (2)")
fmt.Println("end")
start end 4 <nil> defer (2) defer (1)
import "fmt"
{
done := make(chan struct{})
ch := make(chan int)
// producer
go func(){
for i := 0; i < 10; i++ {
ch <- i * i
}
close(ch)
}()
// consumer
go func() {
for i := range ch {
fmt.Printf("i == %d\n", i)
}
close(done)
}()
<-done
}
i == 0 i == 1 i == 4 i == 9 i == 16 i == 25 i == 36 i == 49 i == 64 i == 81
panic("failed!")
panic: failed! goroutine 41 [running]: runtime/debug.Stack(0xc400000008, 0x7f257d12a338, 0xc4204301a0) /usr/lib/go-1.9/src/runtime/debug/stack.go:24 +0xa9 github.com/yunabe/lgo/core.(*resultCounter).recordResult(0xc420430188, 0x7f257cf4f140, 0x7f25705f3970) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:182 +0xce github.com/yunabe/lgo/core.(*resultCounter).recordResultInDefer(0xc420430188) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:187 +0x3b panic(0x7f257cf4f140, 0x7f25705f3970) /usr/lib/go-1.9/src/runtime/panic.go:491 +0x294 github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec3.lgo_init() /home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec3/src.go:6 +0x40 github.com/yunabe/lgo/cmd/runner.loadShared.func3() /home/yunabe/local/gocode/src/github.com/yunabe/lgo/cmd/runner/runner.go:60 +0x26 github.com/yunabe/lgo/core.newRoutineManager.func1(0xc420430180, 0xc42042aad0) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:205 +0x83 created by github.com/yunabe/lgo/core.newRoutineManager /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:202 +0xc5 main routine failed
go func() {
panic("goroutine failed")
}()
panic: goroutine failed goroutine 67 [running]: runtime/debug.Stack(0xc400000008, 0x7f257d12a338, 0xc4204181c0) /usr/lib/go-1.9/src/runtime/debug/stack.go:24 +0xa9 github.com/yunabe/lgo/core.(*resultCounter).recordResult(0xc4204181a8, 0x7f257cf4f140, 0x7f25703ef760) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:182 +0xce github.com/yunabe/lgo/core.FinalizeGoroutine(0xc42032e2c0) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/core/core.go:283 +0x4f panic(0x7f257cf4f140, 0x7f25703ef760) /usr/lib/go-1.9/src/runtime/panic.go:491 +0x294 github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init.func1.1() /home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:12 +0x40 github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init.func1(0xc42032e2c0) /home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:13 +0x4a created by github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4.lgo_init /home/yunabe/local/gocode/src/github.com/yunabe/lgo/sess7b2274696d65223a313531333332343933303133383031353930307d/exec4/src.go:8 +0x4a 1 goroutine failed
reflect
package works with lgo properly.
Note that unexported fields are renamed with LgoExport_
prefix in lgo.
import (
"reflect"
)
type person struct {
Name string
Age int
secret string
}
func (p *person) GetSecret() string {
return p.secret
}
p := &person{Name:"Alice", Age: 12, secret: "1234"}
{
t := reflect.TypeOf(p)
fmt.Println("--- fields ---")
for i := 0; i < t.Elem().NumField(); i++ {
fmt.Printf("field[%d] = %s\n", i, t.Elem().Field(i).Name)
}
fmt.Println("--- methods ---")
for i := 0; i < t.NumMethod(); i++ {
fmt.Printf("method[%d] = %s\n", i, t.Method(i).Name)
}
// Set "Age" via reflect.
v := reflect.ValueOf(p)
v.Elem().Field(1).Set(reflect.ValueOf(34))
fmt.Println("------------")
fmt.Printf("p == %#v\n", p)
}
--- fields --- field[0] = Name field[1] = Age field[2] = LgoExport_secret --- methods --- method[0] = GetSecret ------------ p == &lgo_exec.LgoExport_person{Name:"Alice", Age:34, LgoExport_secret:"1234"}
To display non-text content like HTML, MarkDown and images, use _ctx.Display
.
// Display HTML
_ctx.Display.HTML(
`Hello <b>lgo</b>: <a target="_blank" href="https://github.com/yunabe/lgo" >GitHub lgo</a>
<div style="width:50px;height:50px;background-color:red"></div>`,
nil)
import (
"fmt"
"io/ioutil"
"net/http"
)
var gopherPNG []byte
{
res, err := http.Get("https://golang.org/doc/gopher/frontpage.png")
if err != nil {
fmt.Printf("Failed to get: %v\n", err)
return
}
defer res.Body.Close()
gopherPNG, err = ioutil.ReadAll(res.Body)
if err != nil {
fmt.Printf("Failed to read: %v\n", err)
return
}
_ctx.Display.Text("PNG Gopher", nil)
_ctx.Display.PNG(gopherPNG, nil)
}
PNG Gopher
import (
"bytes"
"image"
jpeg "image/jpeg"
_ "image/png"
"os"
"github.com/nfnt/resize"
)
{
img, _, err := image.Decode(bytes.NewBuffer(gopherPNG))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to decode: %v", err)
return
}
img = resize.Resize(100, 0, img, resize.Lanczos3)
var buf bytes.Buffer
jpeg.Encode(&buf, img, &jpeg.Options{Quality: 1})
_ctx.Display.Text("Resized and highly compressed JPEG", nil)
_ctx.Display.JPEG(buf.Bytes(), nil)
}
Resized and highly compressed JPEG
You can use the second paramter of display methods to overwrite the existing results. See DataDisplayer for details.
import (
"bytes"
"fmt"
"image"
png "image/png"
jpeg "image/jpeg"
"os"
"time"
"github.com/nfnt/resize"
)
{
img, err := png.Decode(bytes.NewBuffer(gopherPNG))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to decode:", err)
return
}
img = resize.Resize(100, 0, img, resize.Lanczos3)
var labelID, imgID string
for quality := 25; quality > 0; quality -= 1 {
var buf bytes.Buffer
jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
size := float32(len(buf.Bytes()))/1000
_ctx.Display.Text(fmt.Sprintf("Quality: %d\nSize: %.2fkB", quality, size), &labelID)
_ctx.Display.JPEG(buf.Bytes(), &imgID)
time.Sleep(200*time.Millisecond)
}
}
Quality: 1 Size: 1.28kB
{
x := 10 + 3.4 +
}
{
for i := 0 {}
}
3:1: expected operand, found '}' 5:5: expected ';', found 'for'
{ // L.1
a := undefined
x := 10
y := 3.4 // L.5
z := x + y
unused := 10
for i := 0; i; i++ {} // L.10
_, _ = a, z
}
2:10: undeclared name: undefined 6:10: invalid operation: mismatched types int and float64 10:17: non-boolean condition in for statement 8:5: unused declared but not used