Why do I like Go language of simple Go language

  • 2020-05-05 11:22:54
  • OfStack

Since 2000, I have been writing code for 11 years, during which I have used VB, Delphi, C#, C++, Ruby, Python, and always looking for a language that suits my mind and philosophy. I was concerned about the feel of writing code and the efficiency of execution, so I never found it until Go came along. After getting familiar with Go, I didn't stop to experience the D language, but I gave it up almost immediately because its design was still too complex.

Let's talk about Go. Its good actually also is two words -- concise!

A lot of my friends' comments don't make any sense with "fewer brackets, fewer semicolons" or anything like that, really? The question is, if you can't have one, why should you? Why are you happy to type more when you can type one less character? Still feel natural? A little simpler here, a little simpler there, is it a lot simpler overall? Is the design simple here, simple there, compact and efficient?

Many things, to the overall experience, to feel really strong. How can you achieve the simplicity of the design without the support of the various "seemingly useless" syntax mentioned above?

I firmly believe that less is more, simple is powerful, not less than a point of the design is really good design!

Concise variable declaration and assignment

For the simplest declaration of variables and assignments, the following sentence completes the declaration type to the assignment, with the usual semicolon at the end of the statement.

var i int = 10;

This is not neat at all, right? Why must there be "var"? Why can't you derive the variable type yourself? Why a semicolon at the end? I'm sure the designers of the Go language have asked these three questions, and have made specific improvements. Start over.

i := 10

Well?" :=" is the syntax sugar for declaring and deriving the type, and the semicolon at the end is also saved, because here I wrap, the compiler understands.

You can also declare and assign multiple variables at once.

i, j, k := 1, 2, 3

Different types can also be used.

i, j, k := 1, 1.0, "hello"

What if you want to declare a bunch of variables, but don't assign them yet? You can do that.

var (

      i, j int       s string
      u, v, s = 2.0, 3.0, "bar")

The designers of Go don't even think they should type "var"!

Concise if

Kind of interesting, right? When I learn a new language, my first glance is at variable types and declarations, and my second is at the syntax of logical control. Now what do we have?


if i > 10 {
    println("Greater then 10")
}

Isn't that common? Can a simple if be simpler? Yes, it is. First of all, the conditional judgment after if is not forced by anyone to add the parenthesis, only two buttons are missing. What else? There are! The following should be a common if usage scenario.


result := SomeMethod()
if result > 0 {
}

A lot of times result is just used for conditional judgment, and you can throw it away after if, so Go has this notation.

if result := SomeMethod(); result > 0 {

}

This expression is so commonly used that it's hard to know who wrote it. Every time I write a line, I get a kick out of it. Take a look at the slightly more convoluted if segment.


if a {
} else if b {
} else if c {
} else {
}

That's fine, but it's not what Go recommends, because it's more concise. Like the mighty switch.

 

Strong switch

This is the well-known use of switch. Notice that there is no break! case does not "underwear" between Go and case.


switch tag {
    default:         s3()
    case 0, 1, 2, 3:        s1()
    case 4, 5, 6, 7:         s2()
}

The magic switch, hehe, is the same as if.


switch x := f(); {  // missing switch expression means "true"
    case x < 0: return -x
    default: return x
}

And this, with this more explicit way of writing it, you really would if... else if... else if... else... ?


switch {
    case x < y: f1()
    case x < z: f2()
    case x == 4: f3()
}

The conditional judgment is comfortable. What about the loop?

 

Lonely for

In fact, I have never quite understood why a language should provide multiple cyclic grammars. for, while, do... while... Are they irreplaceable? Which one? Seems to be a personal hobby? Maybe you can just give an example of how these three things are necessary and subtle, but for me, doing the same thing in multiple ways is actually just redundancy in the design, which is more or less annoying to the user. Take a look at Go's loop.


for i := 0; i < 10; i++ {
}
for a < b {
}
for {
}

See, one for takes care of everything. So let's look at a common traversal set, which is going to look something like this.


count := len(someArray)
for i := 0; i < count; i++ {
    println(someArray[i])
}

To simplify this, Go gives you the keyword "range".


for i, value := range someArray {
    // i It's an integer, it's a subscript
    // value That's the type of value in the array
}

range can be used not just for arrays, but actually for any collection, such as map.


m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for i, s := range a {
    // type of i is int
    // type of s is string
}

There are only a few basic syntax scenarios mentioned here, and there are many more in Go!

 

The function can return multiple values

There are many languages that can be assigned multiple values on a single line, but there are very few that can return multiple values in a single function. For example, in C#, if you want to return two int, this is usually done.


public class TwoInts
{
    public int A;
    public int B;
}
public class Foo
{
    public TwoInts ReturnTwoInt();
}

And then TwoInts ti = foo.CalcTwoInt() sad? Maybe you're numb, right? Many languages are designed this way. The biggest problem with functions that return only one value is that you end up with a lot of unnecessary data structures. This redundancy is shown above. Of course, you say you can use the out keyword to make the function return, but this syntax is not so safe to use. This problem is all too easy to solve in Go, because Go's functions can return multiple values!


func returnTwoInt() (int, int) {
}
a, b := returnTwoInt()

This is where my love affair with Go began, and it took a lot of data structures out of my library! This virtually reduces the complexity of the design.

A pointer to an object declared inside a function can safely return


func ReturnPointer() *Object1 {
    obj := new Object1()
    obj.A = "hello"
    return obj
}

The Go garbage collector will take care of this situation.

 

Exception handling? defer is what? Can eat?

Why is exception handling so complicated? How many people can safely implement the following logic? Here is the pseudocode.


File f = File.Read("c:\\text.txt")
f.Write(xxx)
f.Close()

I'm sure experienced code farmers have versions of try popping up in their heads... catch... finally... There are all kinds of writing conventions, like the logic in "catch" that don't throw exceptions or anything like that. If you think about it, our requirement is simply to open a file and make sure it is closed at the end. That's all. Why does something so simple have to be so complicated? See what Go does!


func SaveSomething() {
    if f, err := os.Open("c:\\text.txt"); err == nil {
        // All kinds of reading and writing
        defer f.Close()
    }
}

Any function with defer will be executed after the current function (in this case, SaveSomething) has been executed. Even if "// various reads and writes "exception f.Close will be firmly executed when SaveSomething exits. With this, free up resources and close a handle is no longer a trivial matter!

 

Interfaces are no longer "implemented"

From the time I was introduced to OO, all languages with interfaces required classes to "implement" interfaces in different ways, which I thought was natural until I met Go.


type Speaker interface {
    Say()
}

An interface is defined above, with only one method, Say, which requires no parameters and returns no value. In Go, anything that has all the methods defined by an interface is implemented by default. This is a sentence with too much connotation, enough to have a significant impact on the design thinking. For example, the following method takes an argument of type Speaker.


func SaySomething(s Speaker) {
    s.Say()
}

So anything that has an Say() method can be thrown in.

In Go's world, everything implements the interface{} interface by default. With this concept, even without generics, design complexity can be effectively reduced.

 

Can multithreading be simpler?

To write multithreading, you need to know Thread, all kinds of locks, all kinds of semaphore. In various systems, "asynchronous" logic usually means "difficult." This is the most powerful part of Go, have you ever seen even simpler asynchronous code than this (the following code is from the official Go example)?


func IsReady(what string, minutes int64) {
    time.Sleep(minutes * 60*1e9);
    fmt.Println(what, "is ready")
}
go IsReady("tea", 6);
go IsReady("coffee", 2);
fmt.Println("I'm waiting....");

As a result, print :

I'm waiting.... (right away)
coffee is ready (2 min later)
tea is ready (6 min later)

The Go language has the syntax "go" built in, and any go methods will be executed asynchronously. What about passing the message before the asynchronous method? Use channel bai. As the name implies, it is a pipe, one to write in, the other waiting to be read.


result := SomeMethod()
if result > 0 {
}
8

Hey, then you see a bunch of Numbers coming out of the console.

I'll leave it here this time. Sorry for the other good things in Go. I'm hungry, so I won't go on the stage. Bow! Go!


Related articles: