【问题标题】:Is there any way to have a safe cast knowing all possible types at compile time?有没有办法在编译时知道所有可能的类型进行安全转换?
【发布时间】:2020-07-08 13:14:11
【问题描述】:

我正在努力解决如何安全地提出论点并确保处理所有可能性。

由于我有 Kotlin 背景,我正在用该语言编写示例:

package question

class StateA(val message: String)
class StateB(val number: Int)
object StateC

fun <State> render(state: State) = when (state) {
    is StateA -> println("state is StateA, its message: ${state.message}")
    is StateB -> println("state is StateB, its number: ${state.number}")
    StateC -> println("state is StateC")
    else -> println("Unknown type")
}

fun main() {
    render(StateA("Hello world")) // prints: state is StateA, its message: Hello world
    render(StateB(42)) // prints: state is StateB, its number: 42
    render(StateC) // prints: state is StateC
    render("Other type") // prints: Unknown type
}

when 语句检查泛型类型 State 并在类型匹配时进行安全强制转换,因此如果类型是 StateA,我可以访问 message,或者如果状态是,我可以访问 number StateB 的实例。

该代码有一个问题,即 else 分支,但我可以通过使用名为 sealed class 的语言功能来摆脱它,并且我在编译时知道所有可能的类型:

package question

import question.State.*

sealed class State {
    class StateA(val message: String) : State()
    class StateB(val number: Int) : State()
    object StateC : State()
}

fun render(state: State) = when (state) {
    is StateA -> println("state is StateA, its message: ${state.message}")
    is StateB -> println("state is StateB, its number: ${state.number}")
    StateC -> println("state is StateC")
}

fun main() {
    render(StateA("Hello world")) // prints: state is StateA, its message: Hello world
    render(StateB(42)) // prints: state is StateB, its number: 42
    render(StateC) // prints: state is StateC
}

我在 Rust 中最接近的是使用 Any:

use std::any::Any;

struct StateA {
    message: String,
}
struct StateB {
    number: u8,
}
struct StateC {}

fn render(state: &dyn Any) {
    if let Some(state_a) = state.downcast_ref::<StateA>() {
        println!("state is StateA, its message: {}", state_a.message);
    } else if let Some(state_b) = state.downcast_ref::<StateB>() {
        println!("state is StateB, its number: {}", state_b.number);
    } else if let Some(_) = state.downcast_ref::<StateC>() {
        println!("state is StateC");
    } else {
        println!("Unknown type")
    }
}

fn main() {
    render(&StateA {
        message: String::from("Hello World"),
    }); // prints: state is StateA, its message: Hello World
    render(&StateB { number: 42 }); // prints: state is StateB, its number: 42
    render(&StateC {}); // prints: state is StateC
    render(&"Other type"); // prints: Unknown type
}

这个解决方案与 Kotlin 中的第一个解决方案类似,所以它有相同的问题,else 分支

有没有办法在编译时知道所有可能的类型进行安全转换?类似于 Kotlin 的密封类解决方案,去掉 else 分支?

【问题讨论】:

  • 为什么不使用an enum
  • 谢谢@Shepmaster,它工作得很好,我从没想过使用枚举,锈枚举比 kotlin/java 宇宙上的枚举更接近密封类。我会用工作代码添加答案,非常感谢!!

标签: generics rust casting


【解决方案1】:

使用Shepmaster's tip to use enums,我设法解决了这个问题。

工作代码:

enum State {
    StateA { message: String },
    StateB { number: u8 },
    StateC,
}

fn render(state: &State) {
    match state {
        State::StateA { message } => println!("state is StateA, its message: {}", message),
        State::StateB { number } => println!("state is StateB, its number: {}", number),
        State::StateC => println!("state is StateC"),
    }
}

fn main() {
    render(&State::StateA {
        message: String::from("Hello World"),
    }); // prints: state is StateA, its message: Hello World
    render(&State::StateB { number: 42 }); // prints: state is StateB, its number: 42
    render(&State::StateC {}); // prints: state is StateC
}

【讨论】:

  • 感谢您的英文和风格更正:)
猜你喜欢
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 2011-01-06
  • 2021-06-12
  • 2021-05-24
  • 2020-09-02
相关资源
最近更新 更多