AI Library · 知识库

# 返回多个信息:同时返回最小值与最大值

学习目标:通过同时计算序列的极值,理解原生多返回值、元组、结构体与模式解构在各语言中的表达差异。

前置知识与范围:循环、数组/列表与基本数据结构。只处理内存中的整数序列。

# 问题与边界

给定一个整数序列,遍历一次并同时返回其中的最小值与最大值:

  1. 正常输入:如 [3, 1, 9, 2],返回 min = 1, max = 9。
  2. 单元素输入:如 [5],返回 min = 5, max = 5。
  3. 空输入边界:由于不存在极值,空序列必须显式拒绝或返回空指示,禁止产生未定义的越界读取或伪造的 0。

# 关键差异

语言 返回形态 调用方解构与接收 空集合契约
Rust 元组 (i32, i32) 包装在 Option 中 let (min, max) = ... 返回 None
Go 原生多返回值 (int, int, error) min, max, err := ... 返回 0, 0, error
Java 记录类 record MinMax(int min, int max) 访问器方法 res.min(), res.max() 抛出 IllegalArgumentException
JavaScript 包含属性的对象 { min, max } 或数组元组 对象解构 const { min, max } = ... 抛出 RangeError
TypeScript 命名属性对象 { readonly min: number; readonly max: number } 对象解构 抛出 RangeError
Kotlin 标准库 Pair<Int, Int> 或数据类 结构化解构 val (min, max) = ... 抛出 NoSuchElementException
Python 原生元组 tuple[int, int] 序列解构 min_val, max_val = ... 抛出 ValueError
C++ std::pair<int, int> 配合 std::optional C++17 结构化绑定 auto [min, max] = ... 返回 std::nullopt

# 各语言实现

# Rust

Rustfn min_max(nums: &[i32]) -> Option<(i32, i32)> {
    if nums.is_empty() {
        return None;
    }
    let mut min = nums[0];
    let mut max = nums[0];
    for &x in &nums[1..] {
        if x < min { min = x; }
        if x > max { max = x; }
    }
    Some((min, max))
}

fn main() {
    assert_eq!(min_max(&[3, 1, 9, 2]), Some((1, 9)));
    assert_eq!(min_max(&[5]), Some((5, 5)));
    assert_eq!(min_max(&[]), None);

    if let Some((min, max)) = min_max(&[3, 1, 9, 2]) {
        println!("min: {min}, max: {max}");
    }
}

Rust 的匿名元组 (i32, i32) 无须提前定义类型结构,通过模式匹配轻松解构。参见 Rust 元组类型。

# Go

Gopackage main

import (
	"errors"
	"fmt"
)

func MinMax(nums []int) (int, int, error) {
	if len(nums) == 0 {
		return 0, 0, errors.New("nums cannot be empty")
	}
	minVal, maxVal := nums[0], nums[0]
	for _, x := range nums[1:] {
		if x < minVal {
			minVal = x
		}
		if x > maxVal {
			maxVal = x
		}
	}
	return minVal, maxVal, nil
}

func main() {
	minVal, maxVal, err := MinMax([]int{3, 1, 9, 2})
	if err != nil || minVal != 1 || maxVal != 9 {
		panic("mismatch")
	}

	sMin, sMax, sErr := MinMax([]int{5})
	if sErr != nil || sMin != 5 || sMax != 5 {
		panic("mismatch on single item")
	}

	if _, _, err := MinMax(nil); err == nil {
		panic("expected error on empty")
	}

	fmt.Printf("min: %d, max: %d\n", minVal, maxVal)
}

Go 在语言层面支持多返回值(Multiple Return Values),无需将结果打包成临时切片或结构体。

# Java

Javaimport java.util.List;

public class Main {
    public record MinMax(int min, int max) {}

    public static MinMax minMax(List<Integer> nums) {
        if (nums == null || nums.isEmpty()) {
            throw new IllegalArgumentException("nums cannot be empty");
        }
        int min = nums.get(0);
        int max = nums.get(0);
        for (int i = 1; i < nums.size(); i++) {
            int x = nums.get(i);
            if (x < min) min = x;
            if (x > max) max = x;
        }
        return new MinMax(min, max);
    }

    public static void main(String[] args) {
        MinMax res = minMax(List.of(3, 1, 9, 2));
        assert res.min() == 1 && res.max() == 9;

        MinMax single = minMax(List.of(5));
        assert single.min() == 5 && single.max() == 5;

        try {
            minMax(List.of());
            assert false : "should fail";
        } catch (IllegalArgumentException expected) {
            // 契约保证
        }

        System.out.println("min: " + res.min() + ", max: " + res.max());
    }
}

Java 16 起引入不可变轻量数据载体 record,通过具名字段消除多返回值的顺序混淆。

# JavaScript

JavaScriptconst assert = {
  equal: (a, b) => { if (a !== b) throw new Error(`${a} !== ${b}`); },
  deepEqual: (a, b) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${JSON.stringify(a)} !== ${JSON.stringify(b)}`); },
  throws: (fn, errType) => {
    try { fn(); throw new Error("expected throw"); } catch (e) {
      if (e.message === "expected throw") throw e;
      if (errType && !(e instanceof errType)) throw e;
    }
  }
};

function minMax(nums) {
  if (!Array.isArray(nums) || nums.length === 0) {
    throw new RangeError("nums cannot be empty");
  }
  let min = nums[0];
  let max = nums[0];
  for (let i = 1; i < nums.length; i++) {
    const x = nums[i];
    if (x < min) min = x;
    if (x > max) max = x;
  }
  return { min, max };
}

const res = minMax([3, 1, 9, 2]);
assert.equal(res.min, 1);
assert.equal(res.max, 9);

const single = minMax([5]);
assert.equal(single.min, 5);
assert.equal(single.max, 5);

assert.throws(() => minMax([]), RangeError);

const { min, max } = res;
console.log(`min: ${min}, max: ${max}`);

JavaScript 返回具有语义属性名的字面量对象,调用方直接运用对象解构语法。

# TypeScript

TypeScriptconst assert = {
  equal: (a: unknown, b: unknown) => { if (a !== b) throw new Error(`${a} !== ${b}`); },
  deepEqual: (a: unknown, b: unknown) => { if (JSON.stringify(a) !== JSON.stringify(b)) throw new Error(`${JSON.stringify(a)} !== ${JSON.stringify(b)}`); },
  throws: (fn: () => void, errType?: unknown) => {
    try { fn(); throw new Error("expected throw"); } catch (e: unknown) {
      if (e instanceof Error && e.message === "expected throw") throw e;
      if (typeof errType === "function" && !(e instanceof errType)) throw e;
    }
  }
};

interface MinMax {
  readonly min: number;
  readonly max: number;
}

function minMax(nums: readonly number[]): MinMax {
  if (nums.length === 0) {
    throw new RangeError("nums cannot be empty");
  }
  let min = nums[0];
  let max = nums[0];
  for (let i = 1; i < nums.length; i++) {
    const x = nums[i];
    if (x < min) min = x;
    if (x > max) max = x;
  }
  return { min, max };
}

const res = minMax([3, 1, 9, 2]);
assert.equal(res.min, 1);
assert.equal(res.max, 9);
assert.throws(() => minMax([]), RangeError);

const { min, max } = res;
console.log(`min: ${min}, max: ${max}`);

TypeScript 定义明确的接口返回类型,防止字段名称拼写错误。

# Kotlin

Kotlinfun minMax(nums: List<Int>): Pair<Int, Int> {
    if (nums.isEmpty()) {
        throw NoSuchElementException("nums cannot be empty")
    }
    var min = nums[0]
    var max = nums[0]
    for (i in 1 until nums.size) {
        val x = nums[i]
        if (x < min) min = x
        if (x > max) max = x
    }
    return Pair(min, max)
}

fun main() {
    val res = minMax(listOf(3, 1, 9, 2))
    check(res.first == 1 && res.second == 9)

    val (min, max) = res
    println("min: $min, max: $max")
}

Kotlin 标准库包含 Pair,支持通过解构声明 val (min, max) = ... 直接解包其成员。

# Python

Pythonfrom typing import Sequence, Tuple

def min_max(nums: Sequence[int]) -> Tuple[int, int]:
    if not nums:
        raise ValueError("nums cannot be empty")
    min_val = nums[0]
    max_val = nums[0]
    for x in nums[1:]:
        if x < min_val:
            min_val = x
        if x > max_val:
            max_val = x
    return min_val, max_val

if __name__ == "__main__":
    assert min_max([3, 1, 9, 2]) == (1, 9)
    assert min_max([5]) == (5, 5)

    try:
        min_max([])
        assert False, "should fail on empty"
    except ValueError:
        pass

    min_val, max_val = min_max([3, 1, 9, 2])
    print(f"min: {min_val}, max: {max_val}")

Python 逗号表达式自动打包为元组,调用方自然解包。

# C++

C++#include <iostream>
#include <vector>
#include <utility>
#include <optional>
#include <cassert>

std::optional<std::pair<int, int>> min_max(const std::vector<int>& nums) {
    if (nums.empty()) {
        return std::nullopt;
    }
    int min_val = nums[0];
    int max_val = nums[0];
    for (size_t i = 1; i < nums.size(); ++i) {
        if (nums[i] < min_val) min_val = nums[i];
        if (nums[i] > max_val) max_val = nums[i];
    }
    return std::make_pair(min_val, max_val);
}

int main() {
    assert(min_max({3, 1, 9, 2}) == std::make_pair(1, 9));
    assert(min_max({5}) == std::make_pair(5, 5));
    assert(min_max({}) == std::nullopt);

    if (auto res = min_max({3, 1, 9, 2})) {
        auto [min_val, max_val] = *res; // C++17 结构化绑定
        std::cout << "min: " << min_val << ", max: " << max_val << "\n";
    }
}

C++17 引入结构化绑定(Structured Binding),可以直接将 std::pair 解包到局部变量中。

# 迁移误区与适用限制

# 运行与验证

语言版本基线见示例基线。 所有程序运行后控制台输出均为:

纯文本min: 1, max: 9

测试断言已完整覆盖多元素、单元素及空输入异常/空值保护。

# 相关阅读