Pregunta y contexto
Go 1.26 elimina la restricción de que un tipo genérico no puede mencionarse a sí mismo en su lista de parámetros de tipo. Explica la restricción a continuación y proporciona una llamada compilable:
type Adder[A Adder[A]] interface {
Add(A) A
}
func SumPair[A Adder[A]](x, y A) A {
return x.Add(y)
}Explica también por qué esta autorreferencia no hace que todos los tipos recursivos sean válidos.
Qué está evaluando el entrevistador
- Si distingues una restricción autorreferencial de un struct infinitamente recursivo.
- Si puedes explicar la satisfacción de restricciones, la sustitución de argumentos de tipo y la comprobación del conjunto de métodos.
- Si puedes instanciar el algoritmo con un tipo concreto y razonar sobre receptores por valor frente a receptores por puntero.
- Si proporcionas salvaguardas de versión, compilador y matriz de pruebas en lugar de limitarte a citar las notas de la versión.
Preguntas aclaratorias para hacer primero
Versión de Go de destino
¿Los compiladores de producción, generadores y CI son todos compatibles con Go 1.26? ¿Debe una biblioteca pública mantenerse compatible con Go 1.25?
Semántica algebraica
¿Requiere Add asociatividad, conmutatividad o ausencia de efectos secundarios? ¿Es el algoritmo una llamada única o un fold sobre una colección arbitraria?
Forma de la instanciación
¿Es la implementación un tipo por valor o por puntero? ¿Debe Add devolver exactamente el tipo del receptor?
Estructura de respuesta de 30 segundos
Go 1.26 permite que una restricción haga referencia al tipo genérico que se está declarando actualmente, habilitando una forma F-bounded como "el argumento implementa operaciones que se devuelven a sí mismo". Adder[A Adder[A]] aún requiere que un argumento concreto proporcione Add(A) A; la instanciación sustituye el argumento antes de comprobar su conjunto de métodos. El cambio amplía las declaraciones de restricciones, no las reglas para la disposición de memoria finita de valores.
Pasos de respuesta a profundidad
1. Explicar el cambio de sintaxis
Las versiones anteriores rechazaban Adder dentro de la restricción de su propio parámetro. Go 1.26 vincula los parámetros de tipo al inicio de la lista, por lo que la restricción puede hacer referencia al tipo genérico que se está declarando. Esto añade poder expresivo sin cambiar las comprobaciones estáticas de métodos de interfaz.
2. Definir un tipo que la satisfaga
type IntAdder int
func (x IntAdder) Add(y IntAdder) IntAdder {
return x + y
}
func example() IntAdder {
return SumPair(IntAdder(2), IntAdder(3))
}IntAdder satisface Adder[IntAdder] porque tanto el parámetro como el resultado utilizan el tipo de argumento instanciado. Un método que devuelva int fallaría incluso cuando la representación subyacente sea la misma.
3. Describir la comprobación de instanciación
Para SumPair[IntAdder], el compilador sustituye IntAdder por A, obtiene Adder[IntAdder] y comprueba el conjunto de métodos de IntAdder. La inferencia de tipos puede inferir A a partir de los argumentos, pero no reemplaza la satisfacción de restricciones.
4. Manejar conjuntos de métodos de puntero
Si Add existe solo en *IntAdder, los llamadores deben usar *IntAdder como argumento y preservar esa forma en el resultado; un valor IntAdder no obtiene automáticamente métodos de puntero. La elección del receptor cambia el conjunto de métodos y no es una conversión genérica.
5. Establecer el límite del tipo recursivo
La autorreferencia está en el grafo de restricciones, como Adder[A]; no es un anidamiento infinito por valor. type Node[T any] struct { Next Node[T] } todavía tiene una disposición de memoria de valor infinitamente grande, mientras que *Node[T] tiene una disposición finita. Los ciclos de restricciones y la disposición concreta son comprobaciones separadas.
6. Evaluar el valor algorítmico
El patrón se adapta a algoritmos genéricos homogéneos como combinar valores o acumular objetos numéricos. No proporciona asociatividad ni demuestra seguridad contra desbordamientos (overflow). Si el algoritmo necesita leyes algebraicas, documéntalas y pruébalas; la presencia del método no es una prueba matemática.
7. Planificar la migración y verificación
Alinea la versión mínima en go.mod, CI e imágenes de release; mantén una ruta con interfaces normales para toolchains más antiguas. Prueba la instanciación exitosa, firmas rechazadas, receptores por valor y por puntero, entradas vacías y límites numéricos, e incluye ejemplos de fallos de compilación en el flujo de trabajo.
Un ejemplo de respuesta de alta calidad
Describiría Adder[A Adder[A]] como la exigencia de un argumento cuyo Add acepte y devuelva ese mismo tipo instanciado, no como un permiso para recursión arbitraria. Primero compilaría IntAdder con un receptor por valor, luego mostraría el límite del conjunto de métodos por puntero. Los llamadores aún suministran el contrato algebraico; la migración bloquea la toolchain a Go 1.26 y utiliza pruebas de compilación positivas y negativas para proteger la restricción.
Errores comunes
- Tratar una restricción autorreferencial como permiso para structs infinitos por valor.
- Ignorar que la firma del método instanciado debe coincidir exactamente con
A. - Asumir que tipos subyacentes idénticos implican conjuntos de métodos de interfaz idénticos.
- Tratar la presencia de métodos como prueba de asociatividad, conmutatividad o ausencia de desbordamiento.
- Publicar sintaxis de Go 1.26 mientras compiladores más antiguos todavía construyen artefactos de producción.
- Probar solo ejemplos exitosos y nunca comprobar restricciones rechazadas o receptores por puntero.
Preguntas y respuestas de seguimiento
¿Es Adder[A Adder[A]] una interfaz recursiva?
Es un patrón de declaración en el que una restricción se refiere al tipo genérico que se está declarando. Tras la sustitución, el compilador comprueba si el argumento implementa la interfaz expandida; eso difiere de un campo que incrusta recursivamente un valor de forma infinita.
¿Por qué type IntAdder int satisface la restricción?
Declara Add(IntAdder) IntAdder, por lo que el receptor y el resultado utilizan exactamente el tipo de argumento instanciado. La identidad del tipo subyacente no puede reemplazar la comprobación de firmas de métodos.
¿Cuándo falla un receptor por puntero?
Falla cuando el argumento es un tipo por valor pero el método solo existe en el conjunto de métodos por puntero. Elige deliberadamente la instanciación por valor o por puntero y mantén consistente la forma del resultado.
¿Garantiza esta restricción la asociatividad?
No. La interfaz describe firmas de métodos invocables. La asociatividad, la política de desbordamiento y los efectos secundarios pertenecen a la documentación, las pruebas o un protocolo de nivel superior.
¿Cómo das soporte a Go 1.25?
Aísla la restricción autorreferencial en archivos o módulos de Go 1.26, utiliza una interfaz normal o una implementación especializada para versiones anteriores y compila ejemplos positivos y negativos con una matriz de CI multiversión.