Как в go вернуть значение функции если результат выполнения имеет разные типы?

Пишу функцию, которая обрабатывает букву Z: она преобразует её в "зет", если Z используется как самостоятельное слово, или в "з", если она входит в состав слова.

Перед обработкой буквы применяется функция, которая заменяет буквосочетания, например "sh" -> "ш" и подобные. Поэтому для обработки я использую руны вместо строк (это позволяет более корректно интерпретировать байты). Как возвращать из функции одно из возможных значений — руну ИЛИ массив рун?

Исходный код:

func Zhandler(a string, i int) (rune || []rune) {
    if i == 0 && utf8.RuneCountInString(a) == 1 {
        return []rune{'з', 'э', 'т'}
    }
    return 'з'
}

Ответы (1 шт):

Автор решения: Pak Uula

Golang - язык со строгой типизацией, и полиморфизм возможен лишь для интерфейсов: если типы А и В реализуют общий интерфейс I, то функция, возвращающая I, может вернуть как объект типа A, так и объект типа B.

rune и []rune - это базовые типы, которые не реализуют никаких интерфейсов, поэтому у них нет общего типа.

Есть много вариантов, как полиморфизм симулировать.

Например, можно возвращать два значения:

func Zhandler(a string, i int) (rune, []rune) {
    if i == 0 && utf8.RuneCountInString(a) == 1 {
        return 0, []rune{'з', 'э', 'т'}
    }
    return 'з', nil
}

В вызывающей стороне достаточно проверить, равно ли второе возвращаемое значение nil

func main() {
    z, zet := Zhandler("test", 0)
    if zet == nil {
        fmt.Println("одна буква Зэ: ", z)
    } else {
        fmt.Println("Зэт: ", zet)
    }
}

Можно сделать структуру ZhandlerReturn

type ZhandlerReturn struct {
    Z   rune
    Zet []rune
}

func Z() ZhandlerReturn {
    return ZhandlerReturn{
        Z:   'з',
        Zet: nil,
    }
}

func Zet() ZhandlerReturn {
    return ZhandlerReturn{
        Z:   0,
        Zet: []rune{'з', 'э', 'т'},
    }
}

func (zh ZhandlerReturn) IsZ() bool {
    return zh.Zet == nil
}

func Zhandler2(a string, i int) ZhandlerReturn {
    if i == 0 && utf8.RuneCountInString(a) == 1 {
        return Zet()
    }
    return Z()
}

Но, если честно, зачем вам отдельная руна? Потом ведь наверняка придётся объединять результат с другими рунными массивами? Поэтому возвращайте в обоих случаях массивы:

var (
    ZE  = []rune("з")
    ZET = []rune("зэт")
)

func Zhandler3(a string, i int) []rune {
    if i == 0 && utf8.RuneCountInString(a) == 1 {
        return ZET
    }
    return ZE
}
→ Ссылка