特征约束
在介绍泛型函数时,我们实现了一个swap函数:
fn[T] swap(arr : Array[T]) -> Unit {
let tmp : T = arr[0]
arr[0] = arr[1]
arr[1] = tmp
}
swap函数只需要移动元素在数组中的位置,它实际上无法对元素本身进行任何操作,
这是因为T对swap内部来说完全是未知的类型:我们不知道T支持什么方法,例如,比较两个元素是否相等,
或者打印元素的值用于调试。
我们可以通过特征约束(trait bounds)来为T增加一个类似于类型标注的标记,
语法为T : Eq,表示T必须实现Eq特征。一个泛型参数声明可以有多个特征约束,
例如T : Eq + Show,表示T必须实现Eq和Show。
这样就保证了我们可以在函数体内安全地使用这些特征的方法。
示例中改变了swap的行为:在交换元素之前,打印 debug 信息。Show特征包含了to_string方法,
因此可以对类型T的值调用to_string方法将其转换为字符串。或者直接在字符串插值中使用。
示例中还包含一个find_index函数,它尝试找到一个元素在数组中的位置。如果存在,返回该元素的索引,否则返回None。
为了比较数组中的元素和目标元素是否相等,我们为泛型参数T添加了Eq特征约束,从而可以调用Eq::equal方法进行比较。
///|
fn[T : Show] swap(arr : Array[T]) -> Unit {
let tmp_str = arr[0].to_string()
let arr1_str = arr[1].to_string()
println("swap \{tmp_str} and \{arr1_str} in array.")
// 和上面的代码等价:
// println("swap \{arr[0]} and \{arr[1]} in array.")
let tmp : T = arr[0]
arr[0] = arr[1]
arr[1] = tmp
}
///|
fn[T : Eq + Show] find_index(array : Array[T], target : T) -> Int? {
for index, elem in array {
if Eq::equal(elem, target) {
println("array[\{index}] = \{elem}, \{elem} == \{target}")
return Some(index)
} else {
println("array[\{index}] = \{elem}, \{elem} != \{target}")
}
}
return None
}
///|
fn main {
let ints = [2, 1, 3, 4, 5]
swap(ints)
let j = find_index(ints, 4)
println("the result is \{j}")
let i = find_index([true, false, true, false], false)
println("the result is \{i}")
}