Skip to content

Go Γλώσσα Προγραμματισμού - Φύλλο Οδηγιών

Η Go (γνωστή και ως Golang) είναι μια στατικά τυποποιημένη, μεταγλωττισμένη γλώσσα που αναπτύχθηκε από τους Robert Griesemer, Rob Pike και Ken Thompson της Google. Η σύνταξη της Go είναι παρόμοια με τη C, αλλά διαθέτει χαρακτηριστικά όπως: ασφάλεια μνήμης, GC (garbage collection), δομική τυποποίηση και ταυτόχρονο προγραμματισμό τύπου CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Μεταβλητές (Variables)

Δήλωση μεταβλητής

var msg string
msg = "Hello"

Σύντομη δήλωση

msg := "Hello"

Σταθερές (Constants)

const Phi = 1.618

Οι σταθερές μπορούν να είναι χαρακτήρες (characters), συμβολοσειρές (strings), λογικές τιμές (booleans) ή αριθμητικές τιμές.

Βασικοί Τύποι

Συμβολοσειρές (Strings)

str := "Hello"
str := `Multiline
string`

Ο τύπος των συμβολοσειρών είναι string.

Αριθμητικοί Τύποι

Τυπικοί τύποι

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias για uint8)

Άλλοι τύποι

var u uint = 7        // uint (unsigned)
var p float32 = 22.7  // 32-bit float

Δείκτες (Pointers)

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Ένας δείκτης δείχνει στη θέση μνήμης μιας μεταβλητής. Η Go διαθέτει πλήρη διαχείριση απορριμμάτων (garbage collection).

Πίνακες (Arrays)

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

Το μέγεθος των πινάκων είναι σταθερό.

Slices (Τμήματα)

slice := []int{2, 3, 4}
slice := []byte("Hello")

Σε αντίθεση με τους πίνακες, τα slices έχουν δυναμικό μέγεθος.

Έλεγχος Ροής

Συνθήκες (Conditional logic)

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Δηλώσεις μέσα στην if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

Η δήλωση if μπορεί να εκτελέσει μια απλή δήλωση πριν από την έκφραση της συνθήκης.

Switch

switch day {
  case "sunday":
    // οι περιπτώσεις δεν "συνεχίζουν" (fall through) από προεπιλογή!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Συναρτήσεις

Lambdas

myfunc := func() bool {
  return x > 10000
}

Οι συναρτήσεις είναι αντικείμενα πρώτης τάξης (first-class objects).

Πολλαπλοί τύποι επιστροφής

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Καθορισμένες τιμές επιστροφής

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

Δηλώνοντας ονόματα για τις τιμές επιστροφής, η εντολή return (χωρίς ορίσματα) θα επιστρέψει τις μεταβλητές με αυτά τα ονόματα.

Πακέτα (Packages)

Φόρτωση (Loading)

import "fmt"
import "math/rand"
import (
  "fmt"        // παρέχει fmt.Println
  "math/rand"  // παρέχει rand.Intn
)

Και οι δύο τρόποι είναι ίδιοι.

Ψευδώνυμα (Aliases)

import r "math/rand"
 
r.Intn()

Ονόματα κλήσης

func Hello () {
  ···
}

Τα ονόματα κλήσης που εξάγονται ξεκινούν με κεφαλαίο γράμμα.

Packages

package hello

Κάθε αρχείο πακέτου πρέπει να ξεκινά με τη δήλωση package.

Ταυτόχρονη Εκτέλεση (Concurrency)

Goroutines

func main() {
  // Ένα "κανάλι" (channel)
  ch := make(chan string)

  // Έναρξη ταυτόχρονων ρουτινών
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Ανάγνωση 3 αποτελεσμάτων
  // (Εφόσον οι goroutines είναι ταυτόχρονες,
  // η σειρά δεν είναι εγγυημένη!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Τα κανάλια είναι αντικείμενα επικοινωνίας ασφαλή για ταυτόχρονη χρήση, που χρησιμοποιούνται μεταξύ των goroutines.

Κανάλια με Buffering

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!

Τα κανάλια με buffer περιορίζουν τον αριθμό των μηνυμάτων που μπορούν να κρατήσουν.

Κλείσιμο καναλιού

ch <- 1
ch <- 2
ch <- 3
close(ch)

Περίληψη καναλιού μέχρι να κλείσει:

for i := range ch {
  ···
}

Κλείσιμο αν ok == false:

v, ok := <- ch

Έλεγχος Σφαλμάτων

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

Καθυστερεί την εκτέλεση μιας συνάρτησης μέχρι να επιστρέψει η συνάρτηση που την περιβάλλει. Τα ορίσματα αξιολογούνται αμέσως, αλλά η κλήση της συνάρτησης εκτελείται στο τέλος.

Συναρτήσεις Defer

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

Οι Lambdas είναι πιο κατάλληλες για μπλοκ καθυστέρησης (defer blocks).

Structure (Δομές)

Ορισμός

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Literals (Κυριολεκτικά)

v := Vertex{X: 1, Y: 2}
// Τα ονόματα των πεδίων μπορούν να παραλειφθούν
v := Vertex{1, 2}
// Το Y είναι έμμεσο
v := Vertex{X: 1}

Μπορείτε επίσης να καθορίσετε τα ονόματα των πεδίων.

Δείκτες σε δομές

v := &Vertex{1, 2}
v.X = 2

Όταν το v είναι δείκτης, το v.X και το (*v).X είναι το ίδιο.

Μέθοδοι (Methods)

Δέκτες (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v: = Vertex{1, 2}
v.Abs()

Δεν υπάρχουν κλάσεις, αλλά μπορείτε να χρησιμοποιήσετε δέκτες για να ορίσετε συναρτήσεις σε τύπους.

Τροποποίηση

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// Το `v` ενημερώνεται