< 返回版块

lithbitren 发表于 2023-01-06 01:15

Tags:泛型,trait,generics

比如我想让一个函数只允许i32usize传入,如何最简单实现这个功能。

找了各种教程书籍也没找到怎么写,于是自己琢磨着写了一个,算是基本实现功能了。

纯泛型加号约束编译不能通过,提示泛型约束必须用trait,于是就实现了个trait。

但像下面这个例子,想要实现a + b就得在泛型里加std::ops::Add<Output = T>的约束,但如果想用基于类型的函数方法,就更复杂了,还得加上eq,ord等一大堆trait约束才行。

trait ConstraintType {}

impl ConstraintType for i32 {}
impl ConstraintType for usize {}

fn add<T: ConstraintType + std::ops::Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

fn main() {
    println!("1 + 2 = {}", add(1, 2));
    println!("3 + 4 = {}", add(3i32, 4i32));
    println!("5 + 6 = {}", add(5usize, 6usize));
    // println!("7 + 8 = {}", add(7i64, 8i64));
    // error[E0277]: the trait bound `i64: ConstraintType` is not satisfied
}

参考ts的类型约束实现起来也有点trick,不加any同样实现不了加运算,不过有js兜底,遇事不决anyscript就完事了。

function add<T extends number | string>(a: T, b: T): T {
	return <any>a + <any>b;
} 

毕竟是小众需求,能实现就不错了,特来发帖跟大家交流交流。

评论区

写评论
作者 lithbitren 2023-01-08 00:35

感谢各位大佬参与讨论,这个主题下很有收获!!

作者 lithbitren 2023-01-08 00:34

虽然还是云里雾里,但基本认可就这么写了。

其实以前抄别人的trait的时候确实基本都有Sized,写写就习惯了。

rfc仿佛天书,看到text列表里这么多内容就发怵。。

--
👇
ifyuhj: 那里的高赞回答讲了它是这样设计的,但具体的原因或动机在这RFC546

👇
lithbitren: 似懂非懂,意思是只要出现了Self传递就得加Sized

出现ops::Add<Output = Self>相当于出现了Self传递,所以得加Sized

那岂不是几乎所有trait继承的时候都得加Sized?有没有继承约束可以不加Sized的例子?

ifyuhj 2023-01-07 12:44

那里的高赞回答讲了它是这样设计的,但具体的原因或动机在这RFC546

👇
lithbitren: 似懂非懂,意思是只要出现了Self传递就得加Sized

出现ops::Add<Output = Self>相当于出现了Self传递,所以得加Sized

那岂不是几乎所有trait继承的时候都得加Sized?有没有继承约束可以不加Sized的例子?

作者 lithbitren 2023-01-07 03:42

似懂非懂,意思是只要出现了Self传递就得加Sized

出现ops::Add<Output = Self>相当于出现了Self传递,所以得加Sized

那岂不是几乎所有trait继承的时候都得加Sized?有没有继承约束可以不加Sized的例子?

--
👇
ifyuhj: 为什么写在trait定义里就要加Sized,写在函数里就不用呢?

答案找到了:https://stackoverflow.com/questions/30938499/why-is-the-sized-bound-necessary-in-this-trait

ifyuhj 2023-01-06 21:13

为什么写在trait定义里就要加Sized,写在函数里就不用呢?

答案找到了:https://stackoverflow.com/questions/30938499/why-is-the-sized-bound-necessary-in-this-trait

xh1109 2023-01-06 21:06

将楼主的问题比喻为要往箱子里面装一个异形布偶.

楼主的操作相当于买来一个通用的纸箱子,在往里面填充减震泡沫而达到目的.

trait ConstraintType {}

impl ConstraintType for i32 {}
impl ConstraintType for usize {}

fn add<T: ConstraintType + std::ops::Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

另一位仁兄相当于是先给这个布偶开了个模. 就是为他定制的箱子.

trait ConstraintType: std::ops::Add<Output = Self> + Sized {}

impl ConstraintType for i32 {}
impl ConstraintType for usize {}

fn add<T: ConstraintType>(a: T, b: T) -> T {
    a + b
}
作者 lithbitren 2023-01-06 19:52

下面那个

--
👇
TLMegalovania: 什么例子

struct Foo<T>(T);
// struct FooUse(Foo<[i32]>); 

还是

trait Bar: Sized { }
struct Impl;
impl Bar for Impl { }
// let y: &dyn Bar = &Impl;

--
👇
lithbitren: 看了没整明白,包括那个例子也没看懂。。主楼是加了sized才能编译通过,标准库例子了加了sized反而编译不了,啥意思啊

--
👇
TLMegalovania: https://doc.rust-lang.org/core/marker/trait.Sized.html

--
👇
lithbitren: 不过为什么写在trait定义里就要加Sized,写在函数里就不用呢?

--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}





ThalliMega 2023-01-06 17:25

什么例子

struct Foo<T>(T);
// struct FooUse(Foo<[i32]>); 

还是

trait Bar: Sized { }
struct Impl;
impl Bar for Impl { }
// let y: &dyn Bar = &Impl;

--
👇
lithbitren: 看了没整明白,包括那个例子也没看懂。。主楼是加了sized才能编译通过,标准库例子了加了sized反而编译不了,啥意思啊

--
👇
TLMegalovania: https://doc.rust-lang.org/core/marker/trait.Sized.html

--
👇
lithbitren: 不过为什么写在trait定义里就要加Sized,写在函数里就不用呢?

--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}




作者 lithbitren 2023-01-06 01:50

看了没整明白,包括那个例子也没看懂。。主楼是加了sized才能编译通过,标准库例子了加了sized反而编译不了,啥意思啊

--
👇
TLMegalovania: https://doc.rust-lang.org/core/marker/trait.Sized.html

--
👇
lithbitren: 不过为什么写在trait定义里就要加Sized,写在函数里就不用呢?

--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}



ThalliMega 2023-01-06 01:38

https://doc.rust-lang.org/core/marker/trait.Sized.html

--
👇
lithbitren: 不过为什么写在trait定义里就要加Sized,写在函数里就不用呢?

--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}


作者 lithbitren 2023-01-06 01:33

不过为什么写在trait定义里就要加Sized,写在函数里就不用呢?

--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}

作者 lithbitren 2023-01-06 01:29

这样写确实更据一般性,实现多个同约束函数时不用重复写ops了

--
👇
TLMegalovania

ThalliMega 2023-01-06 01:25
trait ConstraintType: std::ops::Add<Output = Self> + Sized {}

impl ConstraintType for i32 {}
impl ConstraintType for usize {}

fn add<T: ConstraintType>(a: T, b: T) -> T {
    a + b
}

fn main() {
    println!("1 + 2 = {}", add(1, 2));
    println!("3 + 4 = {}", add(3i32, 4i32));
    println!("5 + 6 = {}", add(5usize, 6usize));
    // println!("7 + 8 = {}", add(7i64, 8i64));
    // error[E0277]: the trait bound `i64: ConstraintType` is not satisfied
}
1 共 13 条评论, 1 页