Rust does not allow function overloading or variadic functions, so a few different options are available to handle different use cases. I will not go into depth about all the options, but I want to show off one of option that I didn’t see in the blog posts I found but instead discovered while working with TcpStreams.
The signature for connect()
is pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self>
and it can be called with a
variety of arguments, without any explicit conversion:
let stream = TcpStream::connect("127.0.0.1:8080")
// or
let stream = TcpStream::connect([[127, 0, 0, 1], 8080])
// or
let stream = TcpStream::connect((Ipv4Addr::new(127, 0, 0, 1), 8080));
This works by implementing the trait ToSocketAddrs
for each of the object types1:
The trait just enforces the existence of the conversion function
pub trait ToSocketAddrs {
/// Converts this object to an iterator of resolved [`SocketAddr`]s.
//...
fn to_socket_addrs(&self) -> io::Result<Self::Iter>;
}
The implementations end up being quite short in most cases2:
impl ToSocketAddrs for SocketAddr {
// ...
}
impl ToSocketAddrs for (String, u16) {
type Iter = vec::IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
(&*self.0, self.1).to_socket_addrs()
}
}