比如我想让一个函数只允许i32
和usize
传入,如何最简单实现这个功能。
找了各种教程书籍也没找到怎么写,于是自己琢磨着写了一个,算是基本实现功能了。
纯泛型加号约束编译不能通过,提示泛型约束必须用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;
}
毕竟是小众需求,能实现就不错了,特来发帖跟大家交流交流。
1
共 13 条评论, 1 页
评论区
写评论感谢各位大佬参与讨论,这个主题下很有收获!!
虽然还是云里雾里,但基本认可就这么写了。
其实以前抄别人的
trait
的时候确实基本都有Sized
,写写就习惯了。rfc仿佛天书,看到text列表里这么多内容就发怵。。
--
👇
ifyuhj: 那里的高赞回答讲了它是这样设计的,但具体的原因或动机在这RFC546
👇
lithbitren: 似懂非懂,意思是只要出现了
Self
传递就得加Sized
?出现
ops::Add<Output = Self>
相当于出现了Self
传递,所以得加Sized
。那岂不是几乎所有
trait
继承的时候都得加Sized
?有没有继承约束可以不加Sized
的例子?那里的高赞回答讲了它是这样设计的,但具体的原因或动机在这RFC546
👇
lithbitren: 似懂非懂,意思是只要出现了
Self
传递就得加Sized
?出现
ops::Add<Output = Self>
相当于出现了Self
传递,所以得加Sized
。那岂不是几乎所有
trait
继承的时候都得加Sized
?有没有继承约束可以不加Sized
的例子?似懂非懂,意思是只要出现了
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
为什么写在trait定义里就要加
Sized
,写在函数里就不用呢?答案找到了:https://stackoverflow.com/questions/30938499/why-is-the-sized-bound-necessary-in-this-trait
下面那个
--
👇
TLMegalovania: 什么例子
还是
--
👇
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: 看了没整明白,包括那个例子也没看懂。。主楼是加了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 {}
看了没整明白,包括那个例子也没看懂。。主楼是加了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 {}
https://doc.rust-lang.org/core/marker/trait.Sized.html
--
👇
lithbitren: 不过为什么写在trait定义里就要加
Sized
,写在函数里就不用呢?--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}
不过为什么写在trait定义里就要加
Sized
,写在函数里就不用呢?--
👇
TLMegalovania: ```rust trait ConstraintType: std::ops::Add<Output = Self> + Sized {}
这样写确实更据一般性,实现多个同约束函数时不用重复写ops了
--
👇
TLMegalovania