特征约束
在介绍泛型函数时,我们实现了一个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}")
}