LINUX.ORG.RU

Объясните Go синтаксис для дебилов.

 


0

1
func Aaa(any interface{}) {

    switch w := any.(type) {
    case int:
        return func_111(w)

    case string:
        return func_222(w)
    }
}

Какой тип у w (который свитчом сравнивается с разными типами)? Выглядит как будто у w тип - это некий TYPETYPE, который можно сравнивать со встроенными типами. Но как тогда этот TYPETYPE успешно уходит в функцию func_111, которая ждёт строго int?

Рассмотрим первый case. Он говорит, что w равно int. Это равноценно тому, что написать if w == int, но это не компилируется.

Я бы ещё понял синтаксис:

func Aaa(any interface{}) {

    switch w := typeof(any) {
    case int:
        return func_111(any)  // w - это носитель названия типа, а не само значение. Само значение - any.

    case string:
        return func_222(any)
    }
}

Т.е. исходный switch-case должно быть можно переписать так:

if int == w {
    fmt.Printf("%d", w)    // INT
} else if string == w {
    fmt.Printf("%s", w)    // STRING
}

Но такой код не компилируется.



Последнее исправление: hlamotron (всего исправлений: 3)

w имеет разные типы в зависимости от case.

Deleted
()

тут идет определение типа у w

outsider ★★
()
Ответ на: комментарий от beastie

Это понятно. Непонятно как работает switch-case. Switch-case - это ведь таблица условий. Он обычно позволяет себя переписать в виде

if int == w {
    fmt.Printf("%d", w)    // INT
} else if string == w {
    fmt.Printf("%s", w)    // STRING
}

Но такой код не компилируется.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Дело в том, что switch whatever.(type) — это особая конструкция языка, предназначенная именно для этого.

ref: https://golang.org/doc/effective_go.html#type_switch

Альтернативный вариант: https://play.golang.org/p/gWTDmAxOjj

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)

Интересно, что, кроме чрезмерного увлечения веществами, помешало сделать этот механизм нормально, т.е. например как в Ceylon:

	Object aaa(Object any) {
		switch(any)
		case (is Integer) {
			return any + 1;
		}
		case (is String) {
			return any.lines;
		}
		else {
			return className(any);
		}
	}
	
	print(aaa(2)); // 3
	print(aaa("Line 1\nLine 2")); // { Line 1, Line 2 }
	print(aaa(4.3)); // ceylon.language.Float

ovk48 ★★★
()
Ответ на: комментарий от ovk48

Я так понимаю, отсутствие Object, как такового, и более статическая типизация. Если any — это interface{} (Object), то у него нет методов + или lines.

deadskif
()
Ответ на: комментарий от beastie

А могу я переписать код так: (вынести присваивание w за switch)

func Aaa(any interface{}) {

    w := any.(type)

    switch (w) {
    case int:
        return func_111(w)

    case string:
        return func_222(w)
    }
}
Если можно, то какой тип будет у w? Разный? Либо int, либо string?

Можно ли написать так?

w := 5

switch(w) {
    case int:    // ЭТО будет работать так?
        fpt.Ptintf("INT\n")
}

hlamotron
() автор топика
Ответ на: комментарий от beastie

PS: и вообще, использование interface{} без острой необходимости — это моветон. ТС, объясни нам, что ты пытаешься сделать. Т.к. похоже, что ты делаешь что-то не то.

beastie ★★★★★
()
Ответ на: комментарий от deadskif

В приведенном примере + или lines вызываются не на Object. В первом кейсе тип any становится Integer, во втором - String, и только в else остается Object'ом.

ovk48 ★★★
()
Ответ на: комментарий от ovk48

Менять тип у переменной — чем это лучше? И каким он будет после switch? На сколько я помню, за switch в go, w определен не будет.

deadskif
()
Ответ на: комментарий от deadskif

Менять тип у переменной — чем это лучше?

1) Тип после приведения может только сужаться, т.е. остается совместим с тем, что был до приведения (допустим, если переменная имеет тип не Object, а Integer|String, то можно использовать только (is Integer) и (is String)).

2) Тип «меняется» только в рамках узкого четко определенного скопа, в котором приведение логически непротиворечиво (is - это проверка + приведение). В данном случае - в рамках case { ... }.

И каким он будет после switch?

За рамками соотв. case будет Object, как его собсно и передали в функцию.

ovk48 ★★★
()
Последнее исправление: ovk48 (всего исправлений: 2)
Ответ на: комментарий от ovk48

1) Тип после приведения может только сужаться, т.е. остается совместим с тем, что был до приведения (допустим, если переменная имеет тип не Object, а Integer|String, то можно использовать только (is Integer) и (is String)).

2) Тип «меняется» только в рамках узкого четко определенного скопа, в котором приведение логически непротиворечиво (is - это проверка + приведение). В данном случае - в рамках case { ... }.

ИМХО, +- тоже самое, что и в Go.

deadskif
()
Ответ на: комментарий от beastie

Что пытается сделать ТС (уже сделол): я делаю паковщик (маршаллер/сериализатор) всех стандартных типов. В моём пакете есть метод Push() который жрёт любой тип и внутри себя решает как его паковать, какой заголовок для него записывать в поток и т.п.

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Ты ищешь reflect, но это совсем отдельная песня. Можешь глянуть как это реализовано в json или asn1.

Ещё могу предложить свою не совсем законченную реализацию bencoder'а (BitTorrent) — там будет наверно по-проще разобраться.

beastie ★★★★★
()
Ответ на: комментарий от beastie

Тем, что паковщик уже написан на плюсах и выдаёт формат, в котором работает вся система уже давно. Использовать какой-то другой формат не вариант.

hlamotron
() автор топика
Ответ на: комментарий от beastie

reflect - это не сериализация, а средство ковыряния в рантайме неизвестных заранее структур. Что «это» реализовано в json и asn1?

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

В общем случае — это инструмент для реализации

паковщик (маршаллер/сериализатор) всех стандартных типов

beastie ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.