本文分享自华为云社区《多语言编程 返回多个不同类型的方法样例》,作者: 张俭 。

背景

你可能会在一些场景下碰到需要返回多个不同类型的方法。比如协议解析读取报文时,更具体地像kubernetes在开始解析Yaml的时候,怎么知道这个类型是属于Deployment还是Service?

C

C语言通常通过使用Struct(结构体)和Union(联合体)的方式来实现这个功能,如下文例子

#include #include #include <string.h>typedef enum {    MONKEY,    COW,    UNKNOWN} AnimalType;typedef struct {    char* description;} Monkey;typedef struct {    char* description;} Cow;typedef struct {    AnimalType type;    union {        Monkey monkey;        Cow cow;    };} Animal;Animal createAnimal(const char* animalType) {    Animal animal;    if (strcmp(animalType, "Monkey") == 0) {        animal.type = MONKEY;        animal.monkey.description = "I am a monkey!";    } else if (strcmp(animalType, "Cow") == 0) {        animal.type = COW;        animal.cow.description = "I am a cow!";    } else {        animal.type = UNKNOWN;    }    return animal;}int main() {    Animal animal1 = createAnimal("Monkey");    if (animal1.type == MONKEY) {        printf("%s\n", animal1.monkey.description);    }    Animal animal2 = createAnimal("Cow");    if (animal2.type == COW) {        printf("%s\n", animal2.cow.description);    }    Animal animal3 = createAnimal("Dog");    if (animal3.type == UNKNOWN) {        printf("Unknown animal type\n");    }    return 0;}

C++

在C++中,我们可以使用基类指针来指向派生类的对象。可以使用动态类型识别(RTTI)来在运行时确定对象的类型

#include #include class Animal {public:    virtual std::string toString() const = 0;};class Monkey : public Animal {public:    std::string toString() const override {        return "I am a monkey!";    }};class Cow : public Animal {public:    std::string toString() const override {        return "I am a cow!";    }};Animal* createAnimal(const std::string& animalType) {    if (animalType == "Monkey") {        return new Monkey();    }    if (animalType == "Cow") {        return new Cow();    }    throw std::runtime_error("Unknown animal type: " + animalType);}int main() {    try {        Animal* animal1 = createAnimal("Monkey");        if (Monkey* monkey = dynamic_cast(animal1)) {            std::cout <toString() << std::endl;        }        delete animal1;        Animal* animal2 = createAnimal("Cow");        if (Cow* cow = dynamic_cast(animal2)) {            std::cout <toString() << std::endl;        }        delete animal2;    }    catch (const std::runtime_error& e) {        std::cerr << e.what() << std::endl;    }    return 0;}

Go

Go的常见处理方式,是返回一个接口或者**interface{}**类型。调用者使用Go语言类型断言来检查具体的类型

package mainimport (    "fmt")type Animal interface {    String() string}type Monkey struct{}func (m Monkey) String() string {    return "I am a monkey!"}type Cow struct{}func (c Cow) String() string {    return "I am a cow!"}func createAnimal(typeName string) (Animal, error) {    switch typeName {    case "Monkey":        return Monkey{}, nil    case "Cow":        return Cow{}, nil    default:        return nil, fmt.Errorf("Unknown animal type: %s", typeName)    }}func main() {    animal1, err := createAnimal("Monkey")    if err != nil {        fmt.Println(err)        return    }    if monkey, ok := animal1.(Monkey); ok {        fmt.Println(monkey)    }    animal2, err := createAnimal("Cow")    if err != nil {        fmt.Println(err)        return    }    if cow, ok := animal2.(Cow); ok {        fmt.Println(cow)    }}

Java

Java语言的常见处理方式,是返回Object类型或者一个基础类型。然后由调用方在进行instance of判断。或者Java17之后,可以使用模式匹配的方式来简化转型

public class MultiTypeReturnExample {    static class Monkey {        @Override        public String toString() {            return "I am a monkey!";        }    }    static class Cow {        @Override        public String toString() {            return "I am a cow!";        }    }    public static Object createAnimal(String type) throws IllegalArgumentException {        switch (type) {            case "Monkey":                return new Monkey();            case "Cow":                return new Cow();            default:                throw new IllegalArgumentException("Unknown animal type: " + type);        }    }    public static void main(String[] args) throws Exception {        Object animal1 = createAnimal("Monkey");        // java8 写法,后面如果明确用做精确的类型,需要强制转换        if (animal1 instanceof Monkey) {            System.out.println(animal1);        }        Object animal2 = createAnimal("Cow");        if (animal2 instanceof Cow) {            System.out.println(animal2);        }        // java17 写法,不需要强制转换        if (createAnimal("Monkey") instanceof Monkey animal3) {            System.out.println(animal3);        }        if (createAnimal("Cow") instanceof Cow animal4) {            System.out.println(animal4);        }    }}

Javascript

动态类型语言,使用instanceof运算符判断

class Animal {    toString() {        return 'I am an animal';    }}class Monkey extends Animal {    toString() {        return 'I am a monkey';    }}class Cow extends Animal {    toString() {        return 'I am a cow';    }}function createAnimal(animalType) {    switch (animalType) {        case 'Monkey':            return new Monkey();        case 'Cow':            return new Cow();        default:            throw new Error(`Unknown animal type: ${animalType}`);    }}try {    const animal1 = createAnimal('Monkey');    if (animal1 instanceof Monkey) {        console.log(animal1.toString());    }    const animal2 = createAnimal('Cow');    if (animal2 instanceof Cow) {        console.log(animal2.toString());    }    const animal3 = createAnimal('Dog');} catch (error) {    console.error(error.message);}

Kotlin

Kotlin可以使用Sealed Class(密封类)和Any类型两种方式。使用Any的场景,与Java返回Object类似。Sealed Class更加安全、更方便一些。

使用Any类型

open class Animalclass Monkey: Animal() {    override fun toString(): String {        return "I am a monkey!"    }}class Cow: Animal() {    override fun toString(): String {        return "I am a cow!"    }}fun createAnimal(type: String): Any {    return when (type) {        "Monkey" -> Monkey()        "Cow" -> Cow()        else -> throw IllegalArgumentException("Unknown animal type: $type")    }}fun main() {    val animal1 = createAnimal("Monkey")    when (animal1) {        is Monkey -> println(animal1)        is Cow -> println(animal1)    }    val animal2 = createAnimal("Cow")    when (animal2) {        is Monkey -> println(animal2)        is Cow -> println(animal2)    }}

使用SealedClass

sealed class Animal {    data class Monkey(val info: String = "I am a monkey!") : Animal()    data class Cow(val info: String = "I am a cow!") : Animal()}fun createAnimal(type: String): Animal {    return when (type) {        "Monkey" -> Animal.Monkey()        "Cow" -> Animal.Cow()        else -> throw IllegalArgumentException("Unknown animal type: $type")    }}fun main() {    val animal1 = createAnimal("Monkey")    when (animal1) {        is Animal.Monkey -> println(animal1.info)        is Animal.Cow -> println(animal1.info)    }    val animal2 = createAnimal("Cow")    when (animal2) {        is Animal.Monkey -> println(animal2.info)        is Animal.Cow -> println(animal2.info)    }}

Python

Python是动态类型的语言,可以简单基于一些条件返回不同类型的对象,然后在接收到返回值之后使用type()函数或isinstance()函数来确定其类型

class Animal:    def __str__(self):        return "I am an animal"class Monkey(Animal):    def __str__(self):        return "I am a monkey"class Cow(Animal):    def __str__(self):        return "I am a cow"def create_animal(animal_type):    if animal_type == "Monkey":        return Monkey()    elif animal_type == "Cow":        return Cow()    else:        raise ValueError(f"Unknown animal type: {animal_type}")def main():    animal1 = create_animal("Monkey")    if isinstance(animal1, Monkey):        print(animal1)    animal2 = create_animal("Cow")    if isinstance(animal2, Cow):        print(animal2)if __name__ == "__main__":    main()

Ruby

Ruby也较为简单,在方法内部直接返回不同类型的对象。然后,可以使用is_a方法或class方法来确定返回对象的实际类型。

class Animal  def to_s    "I am an animal"  endendclass Monkey < Animal  def to_s    "I am a monkey"  endendclass Cow < Animal  def to_s    "I am a cow"  endenddef create_animal(animal_type)  case animal_type  when "Monkey"    Monkey.new  when "Cow"    Cow.new  else    raise "Unknown animal type: #{animal_type}"  endendbegin  animal1 = create_animal("Monkey")  if animal1.is_a? Monkey    puts animal1  end  animal2 = create_animal("Cow")  if animal2.is_a? Cow    puts animal2  endend

Rust

在Rust中,可以使用enum(枚举)来创建一个持有多种不同类型的数据结构。然后使用match语句来做模式匹配。

use std::fmt;enum Animal {    Monkey,    Cow,}impl fmt::Display for Animal {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        match self {            Animal::Monkey => write!(f, "I am a monkey!"),            Animal::Cow => write!(f, "I am a cow!"),        }    }}fn create_animal(animal_type: &str) -> Result {    match animal_type {        "Monkey" => Ok(Animal::Monkey),        "Cow" => Ok(Animal::Cow),        _ => Err(format!("Unknown animal type: {}", animal_type)),    }}fn main() {    match create_animal("Monkey") {        Ok(animal) => match animal {            Animal::Monkey => println!("{}", animal),            _ => (),        },        Err(e) => println!("{}", e),    }    match create_animal("Cow") {        Ok(animal) => match animal {            Animal::Cow => println!("{}", animal),            _ => (),        },        Err(e) => println!("{}", e),    }    match create_animal("Dog") {        Ok(_) => (),        Err(e) => println!("{}", e),    }}

Scala

scala中,可以使用sealed trait和case class来创建一个能够返回多种不同类型的方法。Sealed trait可以定义一个有限的子类集合,可以确保类型安全

sealed trait Animal {  def info: String}case class Monkey() extends Animal {  val info: String = "I am a monkey!"}case class Cow() extends Animal {  val info: String = "I am a cow!"}object MultiTypeReturnExample {  def createAnimal(animalType: String): Animal = {    animalType match {      case "Monkey" => Monkey()      case "Cow" => Cow()      case _ => throw new IllegalArgumentException(s"Unknown animal type: $animalType")    }  }  def main(args: Array[String]): Unit = {    try {      val animal1 = createAnimal("Monkey")      animal1 match {        case Monkey() => println(animal1.info)        case _ =>      }      val animal2 = createAnimal("Cow")      animal2 match {        case Cow() => println(animal2.info)        case _ =>      }    } catch {      case e: IllegalArgumentException => println(e.getMessage)    }  }}

TypeScript

总得来说,和javascript区别不大

abstract class Animal {  abstract toString(): string;}class Monkey extends Animal {  toString(): string {    return 'I am a monkey';  }}class Cow extends Animal {  toString(): string {    return 'I am a cow';  }}function createAnimal(animalType: string): Animal {  switch (animalType) {    case 'Monkey':      return new Monkey();    case 'Cow':      return new Cow();    default:      throw new Error(`Unknown animal type: ${animalType}`);  }}try {  const animal1 = createAnimal('Monkey');  if (animal1 instanceof Monkey) {    console.log(animal1.toString());  }  const animal2 = createAnimal('Cow');  if (animal2 instanceof Cow) {    console.log(animal2.toString());  }  const animal3 = createAnimal('Dog');} catch (error) {  console.error(error.message);}

点击关注,第一时间了解华为云新鲜技术~