Здесь создается какой-то конструктор?

В одном из примеров сортировки они используют следующий код:

package main

import (
 "fmt"
 "sort"
)

type Person struct {
 Name string
 Age int
}

func (p Person) String() string {
 return fmt.Sprintf("%s: %d", p.Name, p.Age)
}

// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person

func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }

func main() {
 people := []Person{
 {"Bob", 31},
 {"John", 42},
 {"Michael", 17},
 {"Jenny", 26},
 }

 fmt.Println(people)
 sort.Sort(ByAge(people))
 fmt.Println(people)

}

Строка с сортировкой немного запутанна для меня:

sort.Sort(ByAge(people))

Создает ли ByAge (люди) какой-то конструктор, который копирует массив, который передается? Я не уверен, что понимаю, как новый тип ByAge имеет доступ к элементам в противном случае.

1 ответ

Синтаксис foo(expr) где foo - тип, а expr - преобразование типа, как описано в спецификации:

Конверсии

Преобразования представляют собой выражения вида T(x) где T - тип, а x - выражение, которое можно преобразовать в тип T

Conversion = Type "(" Expression [ "," ] ")" .

Если тип начинается с оператора * или <-, или если тип начинается с ключевого слова func и не имеет списка результатов, он должен быть заключен в скобки, когда необходимо, чтобы избежать двусмысленности:

*Point(p) // same as *(Point(p))
(*Point)(p) // p is converted to *Point
<-chan int(c) // same as <-(chan int(c))
(<-chan int)(c) // c is converted to <-chan int
func()(x) // function signature func() x
(func())(x) // x is converted to func()
(func() int)(x) // x is converted to func() int
func() int(x) // x is converted to func() int (unambiguous)

Постоянное значение x может быть преобразовано в тип T в любом из этих случаев:

  • x представляется в виде значения типа T
  • x - константа с плавающей запятой, T - тип с плавающей запятой, и x представляется в виде значения типа T после округления с использованием правил IEEE 754 round-to-even. Константа T(x) является округлым значением.
  • x - целочисленная константа, а T - строковый тип. В этом случае применяется то же правило, что и для непостоянного x.

Преобразование константы приводит к типичной константе.

****(iota) // iota value of type ****
float32(2.718281828) // 2.718281828 of type float32
complex128(1) // 1.0 + 0.0i of type complex128
float32(0.49999999) // 0.5 of type float32
string('x') // "x" of type string
string(0x266c) // "♬" of type string
MyString("foo" + "bar") // "foobar" of type MyString
string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant
(*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
int(1.2) // illegal: 1.2 cannot be represented as an int
string(65.0) // illegal: 65.0 is not an integer constant

Непостоянное значение x может быть преобразовано в тип T в любом из этих случаев:

  • x присваивается T
  • x type и T имеют одинаковые базовые типы.
  • x type и T являются неназванными типами указателей, а их базовые типы указателей имеют одинаковые базовые типы.
  • x type и T являются целыми или с плавающей запятой. x и T являются сложными типами.
  • x - целое число или фрагмент байтов или рун, а T - строковый тип.
  • x - строка, а T - фрагмент байтов или рун.

Конкретные правила применяются к (непостоянным) преобразованиям между числовыми типами или к типу строк и из него. Эти преобразования могут изменить представление x и взять на себя затраты времени выполнения. Все другие преобразования меняют только тип, но не представление x.

Не существует лингвистического механизма для преобразования между указателями и целыми числами. Небезопасный пакет реализует эту функциональность в ограниченных условиях.

Дополнительную информацию см. на связанной странице.

licensed under cc by-sa 3.0 with attribution.