github.com/goplus/gop@v1.2.6/doc/docs.md (about) 1 Go+ Quick Start 2 ====== 3 4 Our vision is to **enable everyone to create production-level applications**. 5 6 #### Easy to learn 7 8 * Simple and easy to understand 9 * Smaller syntax set than Python in best practices 10 11 #### Ready for large projects 12 13 * Derived from Go and easy to build large projects from its good engineering foundation 14 15 The Go+ programming language is designed for engineering, STEM education, and data science. 16 17 * **For engineering**: working in the simplest language that can be mastered by children. 18 * **For STEM education**: studying an engineering language that can be used for work in the future. 19 * **For data science**: communicating with engineers in the same language. 20 21 ## How to install 22 23 ### on Windows 24 25 ```sh 26 winget install goplus.gop 27 ``` 28 29 ### on Debian/Ubuntu 30 31 ```sh 32 sudo bash -c ' echo "deb [trusted=yes] https://pkgs.goplus.org/apt/ /" > /etc/apt/sources.list.d/goplus.list' 33 sudo apt update 34 sudo apt install gop 35 ``` 36 37 ### on RedHat/CentOS/Fedora 38 39 ```sh 40 sudo bash -c 'echo -e "[goplus]\nname=Go+ Repo\nbaseurl=https://pkgs.goplus.org/yum/\nenabled=1\ngpgcheck=0" > /etc/yum.repos.d/goplus.repo' 41 sudo yum install gop 42 ``` 43 44 ### on macOS/Linux (Homebrew) 45 46 Install via [brew](https://brew.sh/) 47 48 ```sh 49 $ brew install goplus 50 ``` 51 52 ### from source code 53 54 Note: Requires go1.18 or later 55 56 ```bash 57 git clone https://github.com/goplus/gop.git 58 cd gop 59 60 # On mac/linux run: 61 ./all.bash 62 # On Windows run: 63 all.bat 64 ``` 65 66 Actually, `all.bash` and `all.bat` will use `go run cmd/make.go` underneath. 67 68 69 ## Running in Go+ playground 70 71 If you don't want install Go+, you can write your Go+ programs in Go+ playground. This is the fastest way to experience Go+. 72 73 * Go+ playground based on Docker: https://play.goplus.org/ 74 * Go+ playground based on GopherJS: https://jsplay.goplus.org/ 75 76 And you can share your Go+ code with your friends. 77 Here is my `Hello world` program: 78 * https://play.goplus.org/p/AAh_gQAKAZR. 79 80 81 ## Table of Contents 82 83 <table> 84 <tr><td width=33% valign=top> 85 86 * [Hello world](#hello-world) 87 * [Running a project folder](#running-a-project-folder-with-several-files) 88 * [Comments](#comments) 89 * [Variables](#variables) 90 * [Go+ types](#go-types) 91 * [Strings](#strings) 92 * [Numbers](#numbers) 93 * [Slices](#slices) 94 * [Maps](#maps) 95 * [Module imports](#module-imports) 96 97 </td><td width=33% valign=top> 98 99 * [Statements & expressions](#statements--expressions) 100 * [If..else](#ifelse) 101 * [For loop](#for-loop) 102 * [Error handling](#error-handling) 103 * [Functions](#functions) 104 * [Returning multiple values](#returning-multiple-values) 105 * [Variadic parameters](#variadic-parameters) 106 * [Higher order functions](#higher-order-functions) 107 * [Lambda expressions](#lambda-expressions) 108 * [Structs](#structs) 109 110 </td><td valign=top> 111 112 * [Go/Go+ hybrid programming](#gogo-hybrid-programming) 113 * [Run Go+ in watch mode](#run-go-in-watch-mode) 114 * [Calling C from Go+](#calling-c-from-go) 115 * [Data processing](#data-processing) 116 * [Rational numbers](#rational-numbers) 117 * [List comprehension](#list-comprehension) 118 * [Select data from a collection](#select-data-from-a-collection) 119 * [Check if data exists in a collection](#check-if-data-exists-in-a-collection) 120 * [Unix shebang](#unix-shebang) 121 * [Compatibility with Go](#compatibility-with-go) 122 123 </td></tr> 124 </table> 125 126 127 ## Hello World 128 129 Different from the function call style of most languages, Go+ recommends command style code: 130 131 ```go 132 println "Hello world" 133 ``` 134 135 Save this snippet into a file named `hello.gop`. Now do: `gop run hello.gop`. 136 137 Congratulations - you just wrote and executed your first Go+ program! 138 139 You can compile a program without execution with `gop build hello.gop`. 140 See `gop help` for all supported commands. 141 142 [`println`](#println) is one of the few [built-in functions](#builtin-functions). 143 It prints the value passed to it to standard output. 144 145 To emphasize our preference for command style, we introduce `echo` as an alias for `println`: 146 147 ```coffee 148 echo "Hello world" 149 ``` 150 151 See https://tutorial.goplus.org/hello-world for more details. 152 153 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 154 155 156 ## Running a project folder with several files 157 158 Suppose you have a folder with several .gop files in it, and you want 159 to compile them all into one program. Just do: `gop run .`. 160 161 Passing parameters also works, so you can do: 162 `gop run . --yourparams some_other_stuff`. 163 164 Your program can then use the CLI parameters like this: 165 166 ```go 167 import "os" 168 169 println os.Args 170 ``` 171 172 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 173 174 175 ## Comments 176 177 ```go 178 # This is a single line comment. 179 180 // This is a single line comment. 181 182 /* 183 This is a multiline comment. 184 */ 185 ``` 186 187 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 188 189 190 ## Variables 191 192 ```go 193 name := "Bob" 194 age := 20 195 largeNumber := int128(1 << 65) 196 println name, age 197 println largeNumber 198 ``` 199 200 Variables are declared and initialized with `:=`. 201 202 The variable's type is inferred from the value on the right hand side. 203 To choose a different type, use type conversion: 204 the expression `T(v)` converts the value `v` to the 205 type `T`. 206 207 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 208 209 ### Initialization vs. assignment 210 211 Note the (important) difference between `:=` and `=`. 212 `:=` is used for declaring and initializing, `=` is used for assigning. 213 214 ```go failcompile 215 age = 21 216 ``` 217 218 This code will not compile, because the variable `age` is not declared. 219 All variables need to be declared in Go+. 220 221 ```go 222 age := 21 223 ``` 224 225 The values of multiple variables can be changed in one line. 226 In this way, their values can be swapped without an intermediary variable. 227 228 ```go 229 a, b := 0, 1 230 a, b = b, a 231 println a, b // 1, 0 232 ``` 233 234 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 235 236 237 ## Go+ Types 238 239 ### Primitive types 240 241 ```go ignore 242 bool 243 244 int8 int16 int32 int int64 int128 245 uint8 uint16 uint32 uint uint64 uint128 246 247 uintptr // similar to C's size_t 248 249 byte // alias for uint8 250 rune // alias for int32, represents a Unicode code point 251 252 string 253 254 float32 float64 255 256 complex64 complex128 257 258 bigint bigrat 259 260 unsafe.Pointer // similar to C's void* 261 262 any // alias for Go's interface{} 263 ``` 264 265 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 266 267 ### Strings 268 269 ```go 270 name := "Bob" 271 println name.len // 3 272 println name[0] // 66 273 println name[1:3] // ob 274 println name[:2] // Bo 275 println name[2:] // b 276 277 // or using octal escape `\###` notation where `#` is an octal digit 278 println "\141a" // aa 279 280 // Unicode can be specified directly as `\u####` where # is a hex digit 281 // and will be converted internally to its UTF-8 representation 282 println "\u2605" // ★ 283 ``` 284 285 String values are immutable. You cannot mutate elements: 286 287 ```go failcompile 288 s := "hello 🌎" 289 s[0] = `H` // not allowed 290 ``` 291 292 Note that indexing a string will produce a `byte`, not a `rune` nor another `string`. 293 294 Strings can be easily converted to integers: 295 296 ```go 297 s := "12" 298 a, err := s.int 299 b := s.int! // will panic if s isn't a valid integer 300 ``` 301 302 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 303 304 305 #### String operators 306 307 ```go 308 name := "Bob" 309 bobby := name + "by" // + is used to concatenate strings 310 println bobby // Bobby 311 312 s := "Hello " 313 s += "world" 314 println s // Hello world 315 ``` 316 317 Most Go+ operators must have values of the same type on both sides. You cannot concatenate an 318 integer to a string: 319 320 ```go failcompile 321 age := 10 322 println "age = " + age // not allowed 323 ``` 324 325 We have to either convert `age` to a `string`: 326 327 ```go 328 age := 10 329 println "age = " + age.string 330 ``` 331 332 However, you can replace `age.string` to `"${age}"`: 333 334 ```go 335 age := 10 336 println "age = ${age}" 337 ``` 338 339 Here is a more complex example of `${expr}`: 340 341 ```go 342 host := "example.com" 343 page := 0 344 limit := 20 345 println "https://${host}/items?page=${page+1}&limit=${limit}" // https://example.com/items?page=1&limit=20 346 println "$$" // $ 347 ``` 348 349 350 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 351 352 353 ### Runes 354 355 A `rune` represents a single Unicode character and is an alias for `int32`. 356 357 ```go 358 rocket := '🚀' 359 println rocket // 128640 360 println string(rocket) // 🚀 361 ``` 362 363 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 364 365 366 ### Numbers 367 368 ```go 369 a := 123 370 ``` 371 372 This will assign the value of 123 to `a`. By default `a` will have the 373 type `int`. 374 375 You can also use hexadecimal, binary or octal notation for integer literals: 376 377 ```go 378 a := 0x7B 379 b := 0b01111011 380 c := 0o173 381 ``` 382 383 All of these will be assigned the same value, 123. They will all have type 384 `int`, no matter what notation you used. 385 386 Go+ also supports writing numbers with `_` as separator: 387 388 ```go 389 num := 1_000_000 // same as 1000000 390 ``` 391 392 If you want a different type of integer, you can use casting: 393 394 ```go 395 a := int64(123) 396 b := uint8(12) 397 c := int128(12345) 398 ``` 399 400 Assigning floating point numbers works the same way: 401 402 ```go 403 f1 := 1.0 404 f2 := float32(3.14) 405 ``` 406 407 If you do not specify the type explicitly, by default float literals will have the type of `float64`. 408 409 Float literals can also be declared as a power of ten: 410 411 ```go 412 f0 := 42e1 // 420 413 f1 := 123e-2 // 1.23 414 f2 := 456e+2 // 45600 415 ``` 416 417 Go+ has built-in support for [rational numbers](#rational-numbers): 418 419 ```go 420 a := 1r << 200 // suffix `r` means `rational` 421 b := bigint(1 << 200) 422 ``` 423 424 And you can cast bool to number types (this is NOT supported in Go): 425 426 ```go 427 println int(true) // 1 428 println float64(true) // 1 429 println complex64(true) // (1+0i) 430 ``` 431 432 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 433 434 435 ### Slices 436 437 A slice is a collection of data elements of the same type. A slice literal is a 438 list of expressions surrounded by square brackets. An individual element can be 439 accessed using an *index* expression. Indexes start from `0`: 440 441 ```go 442 nums := [1, 2, 3] 443 println nums // [1 2 3] 444 println nums.len // 3 445 println nums[0] // 1 446 println nums[1:3] // [2 3] 447 println nums[:2] // [1 2] 448 println nums[2:] // [3] 449 450 nums[1] = 5 451 println nums // [1 5 3] 452 ``` 453 454 Type of a slice literal is infered automatically. 455 456 ```go 457 a := [1, 2, 3] // []int 458 b := [1, 2, 3.4] // []float64 459 c := ["Hi"] // []string 460 d := ["Hi", 10] // []any 461 d := [] // []any 462 ``` 463 464 And casting slice literals also works. 465 466 ```go 467 a := []float64([1, 2, 3]) // []float64 468 ``` 469 470 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 471 472 473 ### Maps 474 475 ```go 476 a := {"Hello": 1, "xsw": 3} // map[string]int 477 b := {"Hello": 1, "xsw": 3.4} // map[string]float64 478 c := {"Hello": 1, "xsw": "Go+"} // map[string]any 479 d := {} // map[string]any 480 ``` 481 482 If a key is not found, a zero value is returned by default: 483 484 ```go 485 a := {"Hello": 1, "xsw": 3} 486 c := {"Hello": 1, "xsw": "Go+"} 487 println a["bad_key"] // 0 488 println c["bad_key"] // <nil> 489 ``` 490 491 You can also check, if a key is present, and get its value. 492 493 ```go 494 a := {"Hello": 1, "xsw": 3} 495 if v, ok := a["xsw"]; ok { 496 println "its value is", v 497 } 498 ``` 499 500 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 501 502 503 ## Module imports 504 505 For information about creating a module, see [Modules](#modules). 506 507 Modules can be imported using the `import` keyword: 508 509 ```go 510 import "strings" 511 512 x := strings.NewReplacer("?", "!").Replace("Hello, world???") 513 println x // Hello, world!!! 514 ``` 515 516 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 517 518 519 ### Module import aliasing 520 521 Any imported module name can be aliased: 522 523 ```go 524 import strop "strings" 525 526 x := strop.NewReplacer("?", "!").Replace("Hello, world???") 527 println x // Hello, world!!! 528 ``` 529 530 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 531 532 533 ## Statements & expressions 534 535 536 ### If..else 537 538 In Go+, `if` statements are pretty straightforward and similar to most other languages. 539 Unlike other C-like languages, 540 there are no parentheses surrounding the condition and the braces are always required. 541 542 ```go 543 a := 10 544 b := 20 545 if a < b { 546 println "a < b" 547 } else if a > b { 548 println "a > b" 549 } else { 550 println "a == b" 551 } 552 ``` 553 554 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 555 556 557 ### For loop 558 559 Go+ has only one looping keyword: `for`, with several forms. 560 561 #### `for`/`<-` 562 563 This is the most common form. You can use it with a slice, map, numeric range or custom iterators. 564 565 For information about creating a custom iterators, see [Custom iterators](#custom-iterators). 566 567 ##### Slice `for` 568 569 The `for value <- arr` form is used for going through elements of a slice. 570 571 ```go 572 numbers := [1, 3, 5, 7, 11, 13, 17] 573 sum := 0 574 for x <- numbers { 575 sum += x 576 } 577 println sum // 57 578 ``` 579 580 If an index is required, an alternative form `for index, value <- arr` can be used. 581 582 ```go 583 names := ["Sam", "Peter"] 584 for i, name <- names { 585 println i, name 586 // 0 Sam 587 // 1 Peter 588 } 589 ``` 590 591 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 592 593 594 ##### Map `for` 595 596 ```go 597 m := {"one": 1, "two": 2} 598 for key, val <- m { 599 println key, val 600 // one 1 601 // two 2 602 } 603 for key, _ <- m { 604 println key 605 // one 606 // two 607 } 608 for val <- m { 609 println val 610 // 1 611 // 2 612 } 613 ``` 614 615 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 616 617 618 ##### Range `for` 619 620 You can use `range expression` (`start:end:step`) in for loop. 621 622 ```go 623 for i <- :5 { 624 println i 625 // 0 626 // 1 627 // 2 628 // 3 629 // 4 630 } 631 for i <- 1:5 { 632 println i 633 // 1 634 // 2 635 // 3 636 // 4 637 } 638 for i <- 1:5:2 { 639 println i 640 // 1 641 // 3 642 } 643 ``` 644 645 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 646 647 648 ##### `for`/`<-`/`if` 649 650 All loops of `for`/`<-` form can have an optional `if` condition. 651 652 ```go 653 numbers := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 654 for num <- numbers if num%3 == 0 { 655 println num 656 // 0 657 // 3 658 // 6 659 // 9 660 } 661 662 for num <- :10 if num%3 == 0 { 663 println num 664 // 0 665 // 3 666 // 6 667 // 9 668 } 669 ``` 670 671 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 672 673 674 #### Condition `for` 675 676 ```go 677 sum := 0 678 i := 1 679 for i <= 100 { 680 sum += i 681 i++ 682 } 683 println sum // 5050 684 ``` 685 686 This form of the loop is similar to `while` loops in other languages. 687 The loop will stop iterating once the boolean condition evaluates to false. 688 Again, there are no parentheses surrounding the condition, and the braces are always required. 689 690 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 691 692 693 #### C `for` 694 695 ```go 696 for i := 0; i < 10; i += 2 { 697 // Don't print 6 698 if i == 6 { 699 continue 700 } 701 println i 702 // 0 703 // 2 704 // 4 705 // 8 706 } 707 ``` 708 709 Finally, there's the traditional C style `for` loop. It's safer than the `while` form 710 because with the latter it's easy to forget to update the counter and get 711 stuck in an infinite loop. 712 713 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 714 715 716 #### Bare `for` 717 718 ```go 719 for { 720 // ... 721 } 722 ``` 723 724 The condition can be omitted, resulting in an infinite loop. You can use `break` or `return` to end the loop. 725 726 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 727 728 729 ### Error handling 730 731 We reinvent the error handling specification in Go+. We call them `ErrWrap expressions`: 732 733 ```go 734 expr! // panic if err 735 expr? // return if err 736 expr?:defval // use defval if err 737 ``` 738 739 How to use them? Here is an example: 740 741 ```go 742 import ( 743 "strconv" 744 ) 745 746 func add(x, y string) (int, error) { 747 return strconv.Atoi(x)? + strconv.Atoi(y)?, nil 748 } 749 750 func addSafe(x, y string) int { 751 return strconv.Atoi(x)?:0 + strconv.Atoi(y)?:0 752 } 753 754 println `add("100", "23"):`, add("100", "23")! 755 756 sum, err := add("10", "abc") 757 println `add("10", "abc"):`, sum, err 758 759 println `addSafe("10", "abc"):`, addSafe("10", "abc") 760 ``` 761 762 The output of this example is: 763 764 ``` 765 add("100", "23"): 123 766 add("10", "abc"): 0 strconv.Atoi: parsing "abc": invalid syntax 767 768 ===> errors stack: 769 main.add("10", "abc") 770 /Users/xsw/tutorial/15-ErrWrap/err_wrap.gop:6 strconv.Atoi(y)? 771 772 addSafe("10", "abc"): 10 773 ``` 774 775 Compared to corresponding Go code, It is clear and more readable. 776 777 And the most interesting thing is, the return error contains the full error stack. When we got an error, it is very easy to position what the root cause is. 778 779 How these `ErrWrap expressions` work? See [Error Handling](https://github.com/goplus/gop/wiki/Error-Handling) for more information. 780 781 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 782 783 784 ## Functions 785 786 ```go 787 func add(x int, y int) int { 788 return x + y 789 } 790 791 println add(2, 3) // 5 792 ``` 793 794 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 795 796 797 ### Returning multiple values 798 799 ```go 800 func foo() (int, int) { 801 return 2, 3 802 } 803 804 a, b := foo() 805 println a // 2 806 println b // 3 807 c, _ := foo() // ignore values using `_` 808 ``` 809 810 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 811 812 813 ### Variadic parameters 814 815 ```go 816 func sum(a ...int) int { 817 total := 0 818 for x <- a { 819 total += x 820 } 821 return total 822 } 823 824 println sum(2, 3, 5) // 10 825 ``` 826 827 Output parameters can have names. 828 829 ```go 830 func sum(a ...int) (total int) { 831 for x <- a { 832 total += x 833 } 834 return // don't need return values if they are assigned 835 } 836 837 println sum(2, 3, 5) // 10 838 ``` 839 840 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 841 842 843 ### Higher order functions 844 845 Functions can also be parameters. 846 847 ```go 848 func square(x float64) float64 { 849 return x*x 850 } 851 852 func abs(x float64) float64 { 853 if x < 0 { 854 return -x 855 } 856 return x 857 } 858 859 func transform(a []float64, f func(float64) float64) []float64 { 860 return [f(x) for x <- a] 861 } 862 863 y := transform([1, 2, 3], square) 864 println y // [1 4 9] 865 866 z := transform([-3, 1, -5], abs) 867 println z // [3 1 5] 868 ``` 869 870 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 871 872 873 ### Lambda expressions 874 875 You also can use `lambda expression` to define a anonymous function. 876 877 ```go 878 func transform(a []float64, f func(float64) float64) []float64 { 879 return [f(x) for x <- a] 880 } 881 882 y := transform([1, 2, 3], x => x*x) 883 println y // [1 4 9] 884 885 z := transform([-3, 1, -5], x => { 886 if x < 0 { 887 return -x 888 } 889 return x 890 }) 891 println z // [3 1 5] 892 ``` 893 894 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 895 896 897 ## Structs 898 899 ### Custom iterators 900 901 #### For range of UDT 902 903 ```go 904 type Foo struct { 905 } 906 907 // Gop_Enum(proc func(val ValType)) or: 908 // Gop_Enum(proc func(key KeyType, val ValType)) 909 func (p *Foo) Gop_Enum(proc func(key int, val string)) { 910 // ... 911 } 912 913 foo := &Foo{} 914 for k, v := range foo { 915 println k, v 916 } 917 918 for k, v <- foo { 919 println k, v 920 } 921 922 println {v: k for k, v <- foo} 923 ``` 924 925 **Note: you can't use break/continue or return statements in for range of udt.Gop_Enum(callback).** 926 927 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 928 929 930 #### For range of UDT2 931 932 ```go 933 type FooIter struct { 934 } 935 936 // (Iterator) Next() (val ValType, ok bool) or: 937 // (Iterator) Next() (key KeyType, val ValType, ok bool) 938 func (p *FooIter) Next() (key int, val string, ok bool) { 939 // ... 940 } 941 942 type Foo struct { 943 } 944 945 // Gop_Enum() Iterator 946 func (p *Foo) Gop_Enum() *FooIter { 947 // ... 948 } 949 950 foo := &Foo{} 951 for k, v := range foo { 952 println k, v 953 } 954 955 for k, v <- foo { 956 println k, v 957 } 958 959 println {v: k for k, v <- foo} 960 ``` 961 962 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 963 964 965 ### Deduce struct type 966 967 ```go 968 type Config struct { 969 Dir string 970 Level int 971 } 972 973 func foo(conf *Config) { 974 // ... 975 } 976 977 foo {Dir: "/foo/bar", Level: 1} 978 ``` 979 980 Here `foo {Dir: "/foo/bar", Level: 1}` is equivalent to `foo(&Config{Dir: "/foo/bar", Level: 1})`. However, you can't replace `foo(&Config{"/foo/bar", 1})` with `foo {"/foo/bar", 1}`, because it is confusing to consider `{"/foo/bar", 1}` as a struct literal. 981 982 You also can omit struct types in a return statement. For example: 983 984 ```go 985 type Result struct { 986 Text string 987 } 988 989 func foo() *Result { 990 return {Text: "Hi, Go+"} // return &Result{Text: "Hi, Go+"} 991 } 992 ``` 993 994 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 995 996 997 ### Overload operators 998 999 ```go 1000 import "math/big" 1001 1002 type MyBigInt struct { 1003 *big.Int 1004 } 1005 1006 func Int(v *big.Int) MyBigInt { 1007 return MyBigInt{v} 1008 } 1009 1010 func (a MyBigInt) + (b MyBigInt) MyBigInt { // binary operator 1011 return MyBigInt{new(big.Int).Add(a.Int, b.Int)} 1012 } 1013 1014 func (a MyBigInt) += (b MyBigInt) { 1015 a.Int.Add(a.Int, b.Int) 1016 } 1017 1018 func -(a MyBigInt) MyBigInt { // unary operator 1019 return MyBigInt{new(big.Int).Neg(a.Int)} 1020 } 1021 1022 a := Int(1r) 1023 a += Int(2r) 1024 println a + Int(3r) 1025 println -a 1026 ``` 1027 1028 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1029 1030 1031 ### Auto property 1032 1033 Let's see an example written in Go+: 1034 1035 ```go 1036 import "gop/ast/goptest" 1037 1038 doc := goptest.New(`... Go+ code ...`)! 1039 1040 println doc.Any().FuncDecl().Name() 1041 ``` 1042 1043 In many languages, there is a concept named `property` who has `get` and `set` methods. 1044 1045 Suppose we have `get property`, the above example will be: 1046 1047 ```go 1048 import "gop/ast/goptest" 1049 1050 doc := goptest.New(`... Go+ code ...`)! 1051 1052 println doc.any.funcDecl.name 1053 ``` 1054 1055 In Go+, we introduce a concept named `auto property`. It is a `get property`, but is implemented automatically. If we have a method named `Bar()`, then we will have a `get property` named `bar` at the same time. 1056 1057 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1058 1059 1060 ## Go/Go+ hybrid programming 1061 1062 This is an example to show how to mix Go/Go+ code in the same package. 1063 1064 In this example, we have a Go source file named `a.go`: 1065 1066 ```go 1067 package main 1068 1069 import "fmt" 1070 1071 func p(a interface{}) { 1072 sayMix() 1073 fmt.Println("Hello,", a) 1074 } 1075 ``` 1076 1077 And we have a Go+ source file named `b.gop`: 1078 1079 ```go 1080 func sayMix() { 1081 println "Mix Go and Go+" 1082 } 1083 1084 p "world" 1085 ``` 1086 1087 You can see that Go calls a Go+ function named `sayMix`, and Go+ calls a Go function named `p`. As you are used to in Go programming, this kind of circular reference is allowed. 1088 1089 Run `gop run .` to see the output of this example: 1090 1091 ``` 1092 Mix Go and Go+ 1093 Hello, world 1094 ``` 1095 1096 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1097 1098 1099 ### Run Go+ in watch mode 1100 1101 The `gop` command can run in watch mode so that everytime a Go+ file is changed it is transpiled to a Go file: 1102 1103 ``` 1104 gop watch [-gentest] [dir] 1105 ``` 1106 1107 By default `gop watch` does not convert test files (normally ending with `_test.gop`). You can specify `-gentest` flag to force converting all Go+ files. 1108 1109 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1110 1111 1112 ## Calling C from Go+ 1113 1114 - The `gop c` command (equivalent to the stand-alone `c2go` command) can be used to convert a C project to a Go project. 1115 - `import "C"` and `import "C/xxx"` are used to import a C project converted by c2go. where `import "C"` is short for `import "C/github.com/goplus/libc"`. 1116 - The `C"xxx"` syntax represents C-style string constants. 1117 1118 Here is [an example to show how Go+ interacts with C](https://github.com/goplus/gop/tree/v1.1/testdata/helloc2go). 1119 1120 ```go 1121 import "C" 1122 1123 C.printf C"Hello, c2go!\n" 1124 C.fprintf C.stderr, C"Hi, %7.1f\n", 3.14 1125 ``` 1126 1127 In this example we call two C standard functions `printf` and `fprintf`, passing a C variable `stderr` and two C strings in the form of `C"xxx"` (a Go+ syntax to represent C-style strings). 1128 1129 Run `gop run .` to see the output of this example: 1130 1131 ``` 1132 Hello, c2go! 1133 Hi, 3.1 1134 ``` 1135 1136 Of course, the current Go+ support for C is only a preview version, not to the extent that it is actually available in engineering. As far as libc is concerned, the current migration progress is only about 5%, and it is just the beginning. 1137 1138 In the upcoming Go+ v1.2 version planning, complete support for C is listed as a top priority. Of course, support for cgo and Go templates is also under planning, which is a crucial capability enhancement for Go/Go+ hybrid projects. 1139 1140 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1141 1142 1143 ## Data processing 1144 1145 ### Rational numbers 1146 1147 We introduce rational numbers as primitive Go+ types. We use suffix `r` to denote rational literals. For example, `1r << 200` means a big int whose value is equal to 2<sup>200</sup>. 1148 1149 ```go 1150 a := 1r << 200 1151 b := bigint(1 << 200) 1152 ``` 1153 1154 By default, `1r` will have the type of `bigint`. 1155 1156 And `4/5r` means the rational constant `4/5`. 1157 It will have the type of `bigrat`. 1158 1159 ```go 1160 a := 4/5r 1161 b := a - 1/3r + 3 * 1/2r 1162 println a, b // 4/5 59/30 1163 ``` 1164 1165 Casting rational numbers works like other [primitive types](#primitive-types): 1166 1167 ```go 1168 a := 1r 1169 b := bigrat(1r) 1170 c := bigrat(1) 1171 println a/3 // 0 1172 println b/3 // 1/3 1173 println c/3 // 1/3 1174 ``` 1175 1176 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1177 1178 1179 ### List comprehension 1180 1181 ```go 1182 a := [x*x for x <- [1, 3, 5, 7, 11]] 1183 b := [x*x for x <- [1, 3, 5, 7, 11] if x > 3] 1184 c := [i+v for i, v <- [1, 3, 5, 7, 11] if i%2 == 1] 1185 1186 arr := [1, 2, 3, 4, 5, 6] 1187 d := [[a, b] for a <- arr if a < b for b <- arr if b > 2] 1188 1189 x := {x: i for i, x <- [1, 3, 5, 7, 11]} 1190 y := {x: i for i, x <- [1, 3, 5, 7, 11] if i%2 == 1} 1191 z := {v: k for k, v <- {1: "Hello", 3: "Hi", 5: "xsw", 7: "Go+"} if k > 3} 1192 ``` 1193 1194 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1195 1196 1197 ### Select data from a collection 1198 1199 ```go 1200 type student struct { 1201 name string 1202 score int 1203 } 1204 1205 students := [student{"Ken", 90}, student{"Jason", 80}, student{"Lily", 85}] 1206 1207 unknownScore, ok := {x.score for x <- students if x.name == "Unknown"} 1208 jasonScore := {x.score for x <- students if x.name == "Jason"} 1209 1210 println unknownScore, ok // 0 false 1211 println jasonScore // 80 1212 ``` 1213 1214 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1215 1216 1217 ### Check if data exists in a collection 1218 1219 ```go 1220 type student struct { 1221 name string 1222 score int 1223 } 1224 1225 students := [student{"Ken", 90}, student{"Jason", 80}, student{"Lily", 85}] 1226 1227 hasJason := {for x <- students if x.name == "Jason"} // is any student named Jason? 1228 hasFailed := {for x <- students if x.score < 60} // is any student failed? 1229 ``` 1230 1231 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1232 1233 1234 ## Unix shebang 1235 1236 You can use Go+ programs as shell scripts now. For example: 1237 1238 ```go 1239 #!/usr/bin/env -S gop run 1240 1241 println "Hello, Go+" 1242 1243 println 1r << 129 1244 println 1/3r + 2/7r*2 1245 1246 arr := [1, 3, 5, 7, 11, 13, 17, 19] 1247 println arr 1248 println [x*x for x <- arr, x > 3] 1249 1250 m := {"Hi": 1, "Go+": 2} 1251 println m 1252 println {v: k for k, v <- m} 1253 println [k for k, _ <- m] 1254 println [v for v <- m] 1255 ``` 1256 1257 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1258 1259 1260 ## Compatibility with Go 1261 1262 All Go features will be supported (including partially support `cgo`, see [below](#bytecode-vs-go-code)). 1263 1264 **All Go packages (even these packages use `cgo`) can be imported by Go+.** 1265 1266 ```coffee 1267 import ( 1268 "fmt" 1269 "strings" 1270 ) 1271 1272 x := strings.NewReplacer("?", "!").Replace("hello, world???") 1273 fmt.Println "x:", x 1274 ``` 1275 1276 **And all Go+ packages can also be imported in Go programs. What you need to do is just using `gop` command instead of `go`.** 1277 1278 First, let's make a directory named `14-Using-goplus-in-Go`. 1279 1280 Then write a Go+ package named [foo](https://github.com/goplus/tutorial/tree/main/14-Using-goplus-in-Go/foo) in it: 1281 1282 ```go 1283 package foo 1284 1285 func ReverseMap(m map[string]int) map[int]string { 1286 return {v: k for k, v <- m} 1287 } 1288 ``` 1289 1290 Then use it in a Go package [14-Using-goplus-in-Go/gomain](https://github.com/goplus/tutorial/tree/main/14-Using-goplus-in-Go/gomain): 1291 1292 ```go 1293 package main 1294 1295 import ( 1296 "fmt" 1297 1298 "github.com/goplus/tutorial/14-Using-goplus-in-Go/foo" 1299 ) 1300 1301 func main() { 1302 rmap := foo.ReverseMap(map[string]int{"Hi": 1, "Hello": 2}) 1303 fmt.Println(rmap) 1304 } 1305 ``` 1306 1307 How to build this example? You can use: 1308 1309 ```bash 1310 gop install -v ./... 1311 ``` 1312 1313 Go [github.com/goplus/tutorial/14-Using-goplus-in-Go](https://github.com/goplus/tutorial/tree/main/14-Using-goplus-in-Go) to get the source code. 1314 1315 <h5 align="right"><a href="#table-of-contents">⬆ back to toc</a></h5> 1316 1317 1318 ## Bytecode vs. Go code 1319 1320 Go+ supports bytecode backend and Go code generation. 1321 1322 When we use `gop` command, it generates Go code to covert Go+ package into Go packages. 1323 1324 ```bash 1325 gop run # Run a Go+ program 1326 gop install # Build Go+ files and install target to GOBIN 1327 gop build # Build Go+ files 1328 gop test # Test Go+ packages 1329 gop fmt # Format Go+ packages 1330 gop clean # Clean all Go+ auto generated files 1331 gop go # Convert Go+ packages into Go packages 1332 ``` 1333 1334 When we use [`igop`](https://github.com/goplus/igop) command, it generates bytecode to execute. 1335 1336 ```bash 1337 igop # Run a Go+ program 1338 ``` 1339 1340 In bytecode mode, Go+ doesn't support `cgo`. However, in Go-code-generation mode, Go+ fully supports `cgo`.