梦见你的名字 发表于 2024-2-20 13:06:49

11种编程语言中,返回多个不同类型的方法样例

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

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

C语言通常通过使用Struct(结构体)和Union(联合体)的方式来实现这个功能,如下文例子
#include <stdio.h>
#include <stdlib.h>
#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 <iostream>
#include <stdexcept>

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<Monkey*>(animal1)) {
            std::cout << monkey->toString() << std::endl;
      }
      delete animal1;

      Animal* animal2 = createAnimal("Cow");

      if (Cow* cow = dynamic_cast<Cow*>(animal2)) {
            std::cout << cow->toString() << std::endl;
      }
      delete animal2;
    }
    catch (const std::runtime_error& e) {
      std::cerr << e.what() << std::endl;
    }

    return 0;
}使用SealedClass

package main

import (
    "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)
    }
}Python

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

Ruby也较为简单,在方法内部直接返回不同类型的对象。然后,可以使用is_a方法或class方法来确定返回对象的实际类型。
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);
}Rust

在Rust中,可以使用enum(枚举)来创建一个持有多种不同类型的数据结构。然后使用match语句来做模式匹配。
use std::fmt;enum Animal {    Monkey,    Cow,}impl fmt::Display for Animal {    fn fmt(&self, f: &mut fmt::Formatter
页: [1]
查看完整版本: 11种编程语言中,返回多个不同类型的方法样例