前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rust设计模式:sealed trait 续篇

Rust设计模式:sealed trait 续篇

作者头像
newbmiao
发布2024-04-28 10:07:49
920
发布2024-04-28 10:07:49
举报
文章被收录于专栏:学点Rust学点Rust

之前写sealed trait时没提他在oauth2-rs中怎么用, 为什么用,这个其实在状态接口设计中很有用,今天展开聊聊。

首先复用上篇的代码,为模拟类库,用mod oauth包起来, 并暴露相关结构体

代码语言:javascript
复制
mod oauth {
    use std::marker::PhantomData;

    pub struct EndointSet {}
    pub struct EndpointNotSet {}

    pub trait EndpointState {}

    impl EndpointState for EndointSet {}
    impl EndpointState for EndpointNotSet {}

    pub struct Client<HasAuthUrl = EndpointNotSet, HasTokenUrl = EndpointNotSet>
    where
        HasAuthUrl: EndpointState,
        HasTokenUrl: EndpointState,
    {
        auth_url: Option<String>,
        token_url: Option<String>,
        phantom: std::marker::PhantomData<(HasAuthUrl, HasTokenUrl)>,
    }

    impl<HasAuthUrl: EndpointState, HasTokenUrl: EndpointState> Client<HasAuthUrl, HasTokenUrl> {
        pub fn new() -> Self {
            Client {
                auth_url: None,
                token_url: None,
                phantom: PhantomData,
            }
        }

        pub fn set_auth_url(self, auth_url: &str) -> Client<EndointSet, HasTokenUrl> {
            Client {
                auth_url: Some(auth_url.to_string()),
                token_url: self.token_url,
                phantom: PhantomData,
            }
        }

        pub fn set_token_url(self, token_url: &str) -> Client<HasAuthUrl, EndointSet> {
            Client {
                auth_url: self.auth_url,
                token_url: Some(token_url.to_string()),
                phantom: PhantomData,
            }
        }
    }

    impl<HasTokenUrl: EndpointState> Client<EndointSet, HasTokenUrl> {
        pub fn get_auth_url(&self) -> &str {
            self.auth_url.as_ref().unwrap()
        }
    }

    impl<HasAuthUrl: EndpointState> Client<HasAuthUrl, EndointSet> {
        pub fn get_token_url(&self) -> &str {
            self.token_url.as_ref().unwrap()
        }
    }
}

hack

这样的话,其实不设置token_url也可以绕过编译器检查,直接调用get_token_url

比如自己实现一个带有get_token_url方法的HackEndpointSet

代码语言:javascript
复制
use oauth::*;
struct HackEndpointSet {}
impl EndpointState for HackEndpointSet {}
impl Client<EndointSet, HackEndpointSet> {
    pub fn get_token_url(&self) -> &str {
        "Hacked!"
    }
}
let client =
    Client::<EndointSet, HackEndpointSet>::new().set_auth_url("https://auth.example.com");
// .set_token_url("https://token.example.com");

println!("Auth URL: {}", client.get_auth_url());
println!("Token URL: {}", client.get_token_url());

防止

怎么防止呢?sealed trait刚好就可以

代码语言:javascript
复制
mod oauth {
    // ...
    // sealed trait
    mod private {
        pub trait EndpointStateSealed {}
    }
    pub trait EndpointState: private::EndpointStateSealed {}
    impl private::EndpointStateSealed for EndointSet {}
    impl private::EndpointStateSealed for EndpointNotSet {}
    // ...
}

这样的话,HackEndpointSet就没法实现EndpointState trait

报错就会有sealed trait信息

代码语言:javascript
复制
error[E0277]: the trait bound `HackEndpointSet: EndpointStateSealed` is not satisfied
  --> src/main.rs:71:28
   |
71 |     impl EndpointState for HackEndpointSet {}
   |                            ^^^^^^^^^^^^^^^ the trait `EndpointStateSealed` is not implemented for `HackEndpointSet`
   |
   = help: the following other types implement trait `EndpointStateSealed`:
             oauth::EndointSet
             EndpointNotSet
note: required by a bound in `oauth::EndpointState`
  --> src/main.rs:12:30
   |
12 |     pub trait EndpointState: private::EndpointStateSealed {}
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EndpointState`
   = note: `EndpointState` is a "sealed trait", because to implement it you also need to implement `oauth::private::EndpointStateSealed`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
   = help: the following types implement the trait:
             oauth::EndointSet
             oauth::EndpointNotSet

最后附上oauth2-rs相关代码[1]地址, 感兴趣的可以去看下。

参考资料

[1]

代码: https://github.com/ramosbugs/oauth2-rs/blob/main/src/client.rs

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 菜鸟Miao 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • hack
  • 防止
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档