Привет! Сегодня продолжаем серию мини-квизов в нашем блоге. Этот выпуск (предыдущий здесь) будет посвящен языку Go — будем считать, что это разминка в преддверие GopherCon Russia 2018 (кстати, у нас на этой конференции будет стенд, и мы планируем несколько интересных активностей).


Под катом — семь вопросов и пара пасхалок. Ответы на вопросы выложим апдейтом к посту в понедельник, 26.02. Если будете решать — кладите ответы под спойлер, чтобы не портить другим фана.


Enjoy!



1. Что выведет этот код?


package main
import (
    "fmt"
)

func add(arr []int, v int) {
    arr = append(arr, v)
}

func main() {
    arr := make([]int, 0, 100000)
    fmt.Printf("%v %p\n", arr, &arr)
    add(arr, 10)
    fmt.Printf("%v %p\n", arr, &arr)
}

Варианты ответов:


  • Пустой массив до вызова add, массив из 1 элемента после. Адреса не совпадают.
  • Оба раза пустой массив. Адреса совпадают.
  • Пустой массив до вызова add, массив из 1 элемента после. Адреса совпадают.
  • Оба раза пустой массив. Адреса не совпадают.

2. Что выведет этот код?


package main

import "fmt"

func main() {
    numbers := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    s1 := numbers[:5:8]
    fmt.Println(s1)
    s2 := numbers[::4]
    fmt.Println(s2)

}

Варианты ответов:


  • Массив чисел от 0 до 5, затем массив чисел от 0 до 9
  • Массив чисел от 0 до 4, затем массив чисел от 0 до 9
  • Не скомпилируется
  • Массив чисел от 0 до 4, затем пустой массив.

3. Допустим у вас следующая иерархия:


src/
    package_1/
        p1_a.go
        p1_b.go
        package_2/
            p2_a.go
            package_3/
                p3_sh.go
                p3_bash.go
                p3_zsh.go

Каждый модуль верхнего уровня импортирует модуль нижнего уровня т.е. package_1 импортирует package_2, а тот в свою очередь package_3. В каждом файле объявлена init-функция след. содержания:


func init () {
    fmt.Println(<название файла, например: p1_a.go>)
}

Что будет выведено на экран?


Варианты ответов:


  • Ошибка компиляции: More than one file in package declares init function
  • Порядок не определён
  • p1_a.go
    p1_b.go
    p2_a.go
    p3_a.go
    p3_bash.go
    p3_sh.go
    p3_zsh.go
  • Функции будут вызваны в случайном порядке, но в соответствии с иерархии начиная с нижнего модуля (package_3) и заканчивая верхним (package_1)

4. Чему будут равны константы:


const (
    _ = iota
    Avito
    OLX
    LetGo
    Craiglist = iota 
    eBay
)

Варианты ответов:


  • 1,2,3,4,5
  • Ошибка компиляции: incorrect constant declaration: iota used twice
  • 0, 1, 2, 3, 4
  • 1,2,3,0, 4

5. Опытный программист Роб решил добавить модуль для парсинга данных в стандартную библиотеку своего языка. Одним из модулей парсера будет конечный автомат, войдя в поток, Роб набросал следующий код, что произойдёт в момент первой компиляции?


package main

type state func(x int) state

func start(x int) state {
    if x == 0 {
        return middle
    } else {
        return end
    }
}

func middle(_ int) state {
    return end
}

func end(_ int) state {
    return start
}

func main() {
    state := start(0)
    state = state(1)
    state = state(2)
}

Варианты ответов:


  • Ошибка в коде: произойдёт ошибка во время компиляции "type 'state' used in self declaration"
  • В stdout ничего не выведется, но процесс завершится успешно
  • Runtime ошибка: возникнет бесконечная рекурсия

6. Каким будет результат выполнения кода?


package main

import (
    "fmt"
)

func test() (x int) {
    defer func () {
        x++
    } ()
    x = 1

    return x
}

func main() {
    fmt.Println(test())
}

  • 1
  • 2
  • Compile error

7. Молодой китайский программист Jian Yang решил освоить Go для своего нового гео-стартапа. Начав с обычного Hello World, он решил слегка его модифицировать, дабы освоить конструкцию range… Каким будет результат выполнения кода?


package main

import (
    "fmt"
)

func main() {
    var rc, bc int

    str := "Hello ??"

    for _ = range str {
        rc++
    }
    for _ = range []byte(str){
        bc++
    }

    fmt.Println(rc, bc)
}

Варианты ответов:


  • 8 8
  • 8 12
  • 8 14
  • 8 16



Желаем хорошего дня и ждём ваших ответов в комментариях. Следующий выпуск Avito Quiz планируем сделать по PHP.

Комментарии (16)


  1. SONANT
    20.02.2018 12:06

    Заголовок спойлера
    1 Оба раза пустой массив. Адреса совпадают.
    2 Не скомпилируется
    3 Функции будут вызваны в случайном порядке, но в соответствии с иерархии начиная с нижнего модуля (package_3) и заканчивая верхним (package_1)
    4 1,2,3,4,5
    5 В stdout ничего не выведется, но процесс завершится успешно
    6 2
    7 8 12


    1. dmbreaker
      21.02.2018 17:20
      +1

      Можно было просто ссылку на play.golang.org скинуть :)
      Попортил фан


  1. youROCK
    20.02.2018 16:07

    Я, конечно же, (почти) всё уже проверил сам на play.golang.org, но вот мои оригинальные ответы:

    Скрытый текст
    1. Оба раза пустой массив. Адреса совпадают.
    2. Не скомпилируется (но я думал, что по причине того, что capacity не может быть меньше длины, а не потому что длина обязательна)
    3. Функции будут вызваны в случайном порядке, но в соответствии с иерархии начиная с нижнего модуля (package_3) и заканчивая верхним (package_1)
    4. 1,2,3,0,1 — кстати говоря, такого варианта у вас нет, видимо опечатка
    5. В stdout ничего не выведется, но процесс завершится успешно — но за такой код я бы наказывал
    6. 2
    7. 8 14 — строго говоря, программисты на Го вряд ли должны знать ширину китайских иероглифов в UTF-8. Тут скорее важно, что сами ответы будут разные при итерации по символам и по байтам.


  1. mirrr
    20.02.2018 22:42

    Скрытый текст
    1) передача слайса значением. Изменить данные мы конечно сможем, но длинну нет, а она 0.
    2) никогда не использовал тройную запись, могу только предположить, что размерность 4 будет меньше длинны здесь: [::4]
    3) конечно, иерархия должна присутствовать, иначе мы рискуем использовать подпакет, который не инициализирован.
    4) iota сбрасывается каждый блок const, а он тут один.
    5) в stdout, собственно, ничего и не выводим. Но это ж не причина для паники)
    6) тут и объяснять ничего не надо, достаточно заменить return x на return, для тех, кто не заметил именованные возвратные значения
    7) да кто их знает, сколько байт один иероглиф займет?)


    1. Stronix
      21.02.2018 16:17
      +1

      Изменить данные мы конечно сможем, но длинну нет, а она 0.

      Но, кстати, мы можем таки получить доступ к данным:
      fmt.Printf("%v %p\n", arr[:1], &arr)


      1. mirrr
        21.02.2018 18:58

        А если так?)
        play.golang.org/p/VUwd0G21182


        1. Stronix
          21.02.2018 19:14

          С нулевой ёмкостью шах и мат, да) (если не использовать unsafe)


  1. dronnix
    21.02.2018 13:19
    +3

    Спасибо, вот вам в благодарность тоже задачка:


    package main
    
    import "fmt"
    
    func main() {
        for i := 0; i < 3; i++ {
            defer func() {
                fmt.Println(i)
            }()
        }
    }


    1. claygod
      21.02.2018 16:10

      Чтобы ваш код работал так, как возможно, предполагается (ну на первый взгляд), надо после инициализации цикла добавить i:=i, а ещё лучше вот так:

      package main
      
      import "fmt"
      
      func main() {
          for i := 0; i < 3; i++ {
              defer func(i int) {
                  fmt.Println(i)
              }(i)
          }
      }


      1. RidgeA
        21.02.2018 16:51

        Думаю в этом и фишка, что код работает не так как кажется на первый взгляд…


        1. youROCK
          21.02.2018 18:33

          Как раз он работает именно так, как кажется на первый взгляд — печатает 3 раза одно и то же число :). Другой вопрос, что наверное в цикле defer вызывать – не лучшая идея :).


      1. youROCK
        21.02.2018 18:32
        +1

        А ещё лучше просто вот так:

        package main
        
        import "fmt"
        
        func main() {
            for i := 0; i < 3; i++ {
                    defer fmt.Println(i)
            }
        }
        


        Потому что аргументы для вызова функции вычисляются на момент вызова defer


  1. niamster
    22.02.2018 03:39

    Вопрос знатокам Go по именным возвращаемым значениям, вы можете мне указать где в спецификации описывается следующее поведение:

    package main
    
    import (
        "fmt"
    )
    
    func test() (x int) {
        x = 1
        defer func () {
            x++
        } ()
    
        return 2
    }
    
    func main() {
        fmt.Println(test())
    }
    


    Спасибо


    1. Stronix
      22.02.2018 09:04

      Отложенные ф-ции выполняются после возвращения из основной, т.е. сначала будет выполнено return 2 (x = 2), а затем x++.


      1. niamster
        23.02.2018 16:40

        Спасибо за ответ. Я имел в виду где описывается поведение `return 2` == `x = 2; return x`?


    1. Stronix
      22.02.2018 09:16

      golang.org/ref/spec#Return_statements

      A «return» statement that specifies results sets the result parameters before any deferred functions are executed.