How to Use the new(value) Syntax for Creating Pointers to Literals in Go 1.26

Go 1.26 introduces the new(value) expression as a concise alternative to address-of literals, eliminating the need for temporary variables when creating pointers to non-zero values.

The new_expression guideline in the JetBrains/go-modern-guidelines repository documents this modern idiom for pointer allocation. According to the source code, this syntax provides a cleaner alternative to the illegal &value pattern that required workarounds in earlier Go versions.

Understanding the new(value) Syntax in Go 1.26

Before Go 1.26, obtaining a pointer to a literal value required cumbersome workarounds. You could not use the address-of operator on raw literals like &42, forcing developers to declare temporary variables solely to take their addresses.

The new(value) syntax—implemented as the new_expression guideline in the JetBrains repository—changes this pattern. While you cannot pass the literal directly to new() (e.g., new(42) is invalid), you allocate the typed pointer and assign the value in two steps:

p := new(int)  // Allocates *int pointing to zero value
*p = 42        // Assigns literal value

This approach eliminates the temporary variable declaration while maintaining type safety and clarity.

Why new(42) Is Not Valid

The analysis explicitly notes that passing literals directly to the new built-in function remains invalid syntax:

p := new(42) // ❌ not valid – use the type directly

Instead, new() requires a type parameter (new(int), new(string), new(MyStruct)), returning a pointer to a zero-valued instance of that type. You then dereference the pointer to assign your literal value.

Practical Code Examples

The following patterns demonstrate idiomatic usage of the new_expression guideline as validated in the repository's test suite.

Basic Pointer to Zero-Valued int

p := new(int)   // *int, points to 0
fmt.Println(*p) // prints 0

Pointer to Non-Zero Literal

p := new(int)
*p = 42
fmt.Println(*p) // prints 42

Struct Literals with new()

For composite types, allocate the struct pointer first, then assign the literal:

type Point struct{ X, Y int }

p := new(Point)        // *Point, zero-valued fields
*p = Point{X: 5, Y: 7} // assign literal
fmt.Println(p.X, p.Y)  // prints: 5 7

Anonymous Struct Types

The syntax works with anonymous struct declarations:

p := new(struct{ Name string; Age int })
*p = struct{ Name string; Age int }{Name: "Alice", Age: 30}
fmt.Printf("%+v\n", *p) // {Name:Alice Age:30}

Comparison: Old vs. Modern Approaches

Before Go 1.26, taking the address of a literal caused a compile error:

// Before Go 1.26 (illegal):
// p := &42 // compile error

// Workaround required temporary variable:
v := 42
p := &v // introduces temporary variable

// Modern Go 1.26 idiom:
p := new(int)
*p = 42

Implementation in JetBrains/go-modern-guidelines

The repository structures this guidance as a formal guideline named new_expression. According to the source analysis, the guideline appears in several key files.

The test suite in internal/guidelines/guidelines_test.go validates guideline ordering. Line 12 specifically checks that the new_expression guideline appears first for Go 1.26:

// internal/guidelines/guidelines_test.go#L12
// Validates new_expression guideline priority for Go 1.26

The guideline definition resides in internal/guidelines/guidelines.go, containing the description, examples, and migration paths from temporary variable patterns.

The project README references this feature as a hallmark of modern Go idioms, citing "new(42) to get a pointer to a value" as an example of cleaner syntax—though as noted, the actual implementation requires type specification followed by dereferenced assignment.

Summary

  • Go 1.26 introduces the new(value) pattern through the new_expression guideline, offering a cleaner alternative to temporary variable declarations.
  • The syntax requires type allocation first: new(int) returns *int, not new(42).
  • Repository validation: The JetBrains/go-modern-guidelines project enforces this pattern through test validation in internal/guidelines/guidelines_test.go.
  • Composite literals work seamlessly: allocate with new(StructType), then assign the literal value via dereference.
  • This approach eliminates the pre-1.26 restriction where &value on literals caused compilation errors.

Frequently Asked Questions

What is the difference between new(value) and &value in Go 1.26?

The &value syntax remains illegal for basic literals (like &42) in Go 1.26. The new(value) pattern—specifically new(Type) followed by dereferenced assignment—provides the same outcome without requiring a named temporary variable. The new built-in allocates memory and returns a pointer, whereas & can only take the address of existing variables or composite literals.

Can I use new(42) to directly create a pointer to the integer 42?

No. According to the internal/guidelines/guidelines.go implementation, new(42) is invalid syntax. You must specify the type: p := new(int) allocates a pointer to a zero-valued integer, then *p = 42 assigns the value. The README cites "new(42)" conceptually, but the actual implementation requires the two-step type-then-assign approach.

Which files in the JetBrains repository define the new_expression guideline?

The guideline is defined in internal/guidelines/guidelines.go, with test coverage in internal/guidelines/guidelines_test.go. The test file specifically validates at line 12 that new_expression appears first in the Go 1.26 guidelines list. Usage examples also appear in the repository's README.md.

Is using new() more efficient than temporary variables?

Yes. Using new(Type) followed by dereferenced assignment avoids allocating a named temporary variable on the stack or heap, depending on escape analysis. This produces cleaner assembly and more readable code by eliminating variables that exist solely to have their addresses taken.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →